https://sichardt.net/mediawiki/index.php?title=Spezial:Neue_Seiten&feed=atom&hidebots=1&hideredirs=1&limit=50&offset=&namespace=0&username=&tagfilter=&size-mode=max&size=0
sichardt - Neue Seiten [de]
2024-03-29T14:46:31Z
Aus sichardt
MediaWiki 1.37.1
https://sichardt.net/mediawiki/index.php/Xiaomi_Mijia_lywsd03mmc
Xiaomi Mijia lywsd03mmc
2023-08-29T18:49:24Z
<p>Gabriel: </p>
<hr />
<div>Xiaomi Mijia lywsd03mmc<br />
<br />
ESP32 Code:<br />
<source lang="C"><br />
//#include <BLEDevice.h><br />
#include "NimBLEDevice.h"//needs about 50% ROM of std BLEDevice.h include<br />
#include <SimpleTimer.h><br />
#include <WiFi.h><br />
#include <WiFiClientSecure.h><br />
#include <HTTPClient.h><br />
<br />
#define ssid "yourSSID"<br />
#define password "yourPSK"<br />
<br />
const char* host = "https://yourserver.net/folder/";<br />
String post_request;<br />
<br />
unsigned int wifi_start;<br />
unsigned int t_sleep;<br />
float temp,humi;<br />
<br />
String addr="00:00:00:00:00:00";<br />
BLEClient* pClient;<br />
bool connectionSuccessful = false;<br />
// The remote service we wish to connect to.<br />
static BLEUUID serviceUUID("ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6");<br />
// The characteristic of the remote service we are interested in.<br />
static BLEUUID charUUID("ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6");<br />
<br />
//prototypes<br />
int wifi_getAddr(int id);<br />
void ble();<br />
int wifi_post(int id);<br />
<br />
<br />
<br />
//wifi functions<br />
void initWiFi() {<br />
<br />
WiFi.mode(WIFI_STA);<br />
wifi_start=millis();<br />
WiFi.begin(ssid, password);<br />
Serial.print("Connecting to WiFi ..");<br />
while (WiFi.status() != WL_CONNECTED) {<br />
Serial.print('.');<br />
delay(1000);<br />
}<br />
Serial.println(WiFi.localIP());<br />
}<br />
<br />
//ESP main functions<br />
void setup() {<br />
Serial.begin(9600);<br />
}<br />
<br />
void loop() {<br />
for (int id=1;id<99;id++){<br />
wifi_getAddr(id);<br />
if(addr=="end" or addr=="00:00:00:00:00:00"){<br />
Serial.println("no valid MIJIA address...");<br />
break;<br />
}<br />
Serial.println(id);<br />
ble();<br />
delay(15000);<br />
if(connectionSuccessful == true){<br />
wifi_post(id);<br />
}else{<br />
Serial.print("could not get data from ");Serial.println(addr);<br />
}<br />
}<br />
Serial.println("sleeping for approx. 25 minutes.");<br />
delay(25*60*1000);<br />
}<br />
<br />
//Bluetooth functions<br />
void ble(){<br />
connectionSuccessful = false;<br />
//ble_addr_t baddr = ble_addr_t(addr);<br />
static BLEAddress htSensorAddress(addr.c_str());<br />
Serial.print("Starting MJ client. addr: "); Serial.println(addr);<br />
delay(750);<br />
<br />
BLEDevice::init("ESP32");<br />
createBleClientWithCallbacks();<br />
delay(750);<br />
connectSensor(htSensorAddress);<br />
registerNotification();<br />
}<br />
<br />
class MyClientCallback : public BLEClientCallbacks {<br />
void onConnect(BLEClient* pclient) {<br />
Serial.println("Connected");<br />
}<br />
<br />
void onDisconnect(BLEClient* pclient) {<br />
Serial.println("Disconnected");<br />
if (!connectionSuccessful) {<br />
Serial.println("RESTART");<br />
ESP.restart();<br />
}<br />
}<br />
};<br />
<br />
void createBleClientWithCallbacks() {<br />
pClient = BLEDevice::createClient();<br />
pClient->setClientCallbacks(new MyClientCallback());<br />
}<br />
<br />
void connectSensor(BLEAddress htSensorAddress) {<br />
pClient->connect(htSensorAddress);<br />
//connectionSuccessful = true;<br />
}<br />
<br />
<br />
<br />
static void notifyCallback(<br />
BLERemoteCharacteristic* pBLERemoteCharacteristic,<br />
uint8_t* pData,<br />
size_t length,<br />
bool isNotify) {<br />
Serial.print("Notify callback for characteristic ");<br />
Serial.println(pBLERemoteCharacteristic->getUUID().toString().c_str());<br />
temp = (pData[0] | (pData[1] << 8)) * 0.01; //little endian <br />
humi = pData[2];<br />
Serial.printf("temp = %.1f : humidity = %.1f \n", temp, humi);<br />
connectionSuccessful = true;<br />
pClient->disconnect();<br />
// BLEDevice::deinit();<br />
<br />
}<br />
<br />
void registerNotification() {<br />
<br />
// Obtain a reference to the service we are after in the remote BLE server.<br />
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);<br />
if (pRemoteService == nullptr) {<br />
Serial.print("Failed to find our service UUID: ");<br />
Serial.println(serviceUUID.toString().c_str());<br />
pClient->disconnect();<br />
return;<br />
}<br />
Serial.println(" - Found our service");<br />
<br />
// Obtain a reference to the characteristic in the service of the remote BLE server.<br />
BLERemoteCharacteristic* pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);<br />
if (pRemoteCharacteristic == nullptr) {<br />
Serial.print("Failed to find our characteristic UUID: ");<br />
Serial.println(charUUID.toString().c_str());<br />
pClient->disconnect();<br />
return;<br />
}<br />
Serial.println(" - Found our characteristic");<br />
pRemoteCharacteristic->registerForNotify(notifyCallback);<br />
}<br />
<br />
<br />
<br />
//server connection functions<br />
<br />
int wifi_post(int id){<br />
WiFiClientSecure wificlient;<br />
initWiFi();<br />
HTTPClient https;<br />
wificlient.setInsecure();//do not check certificate fingerprint<br />
bool dbg_serial=true;<br />
bool error = false;<br />
<br />
while (WiFi.status() != WL_CONNECTED) { //No WIFI yet? Wait.<br />
if (WiFi.status() == WL_CONNECT_FAILED) {<br />
error = true;<br />
break;<br />
}<br />
if (millis() - wifi_start > 30000) {<br />
error = true;<br />
break;<br />
}<br />
delay(500); if (dbg_serial) {<br />
Serial.print(".");HTTPClient https;<br />
}<br />
}<br />
if (dbg_serial) {<br />
if (WiFi.status() == WL_CONNECTED) {<br />
Serial.println("");<br />
Serial.println("Connected to " + String(ssid) + " with IP address " + WiFi.localIP().toString() );<br />
}<br />
if (WiFi.status() != WL_CONNECTED) {<br />
Serial.println("");<br />
Serial.println("Error: No WIFI connection");<br />
}<br />
}<br />
if (error) {<br />
return 0;<br />
}<br />
post_request="t_rh.php?dummy=0&t="+String(temp)+"&rh="+String(humi)+"&id="+String(id);<br />
<br />
https.begin(wificlient, host+post_request); //request destination<br />
https.addHeader("Content-Type", "application/x-www-form-urlencoded"); //content-type header<br />
int httpCode = https.POST(post_request); //send request<br />
delay(150); //wait for ack packet<br />
if ( httpCode != 200 ) {<br />
error = true;<br />
// warn = true;<br />
}<br />
if (dbg_serial) {<br />
Serial.println("requesting: " + post_request);<br />
Serial.println("HTTP Status: " + httpCode );<br />
String response = https.getString();<br />
response.trim();//I get a leading linebreak, therefore trim the results (removes leading and trailing whitespaces)<br />
<br />
Serial.println("response: " + response ); //Print request response payload<br />
}<br />
https.end(); //close connection<br />
return httpCode;<br />
}<br />
<br />
//=================GET NEW MIJIA ADDRESS FROM SERVER =========================================<br />
int wifi_getAddr(int id){<br />
//new address, so reset t and rh<br />
temp=-99; humi=-99;<br />
addr="00:00:00:00:00:00";<br />
<br />
WiFiClientSecure wificlient;<br />
initWiFi();<br />
HTTPClient https;<br />
wificlient.setInsecure();//do not check certificate fingerprint<br />
bool dbg_serial=true;<br />
bool error = false;<br />
<br />
while (WiFi.status() != WL_CONNECTED) { //No WIFI yet? Wait.<br />
if (WiFi.status() == WL_CONNECT_FAILED) {<br />
error = true;<br />
break;<br />
}<br />
if (millis() - wifi_start > 30000) {<br />
error = true;<br />
break;<br />
}<br />
delay(500); if (dbg_serial) {<br />
Serial.print(".");HTTPClient https;<br />
}<br />
}<br />
if (dbg_serial) {<br />
if (WiFi.status() == WL_CONNECTED) {<br />
Serial.println("");<br />
Serial.println("Connected to " + String(ssid) + " with IP address " + WiFi.localIP().toString() );<br />
}<br />
if (WiFi.status() != WL_CONNECTED) {<br />
Serial.println("");<br />
Serial.println("Error: No WIFI connection");<br />
}<br />
}<br />
if (error) {<br />
return 1;<br />
}<br />
post_request="sensoren.php?dummy=0&id="+String(id)+"&type=addr";<br />
<br />
https.begin(wificlient, host+post_request); //request destination<br />
https.addHeader("Content-Type", "application/x-www-form-urlencoded"); //content-type header<br />
int httpCode = https.POST(post_request); //send request<br />
delay(150); //wait for ack packet<br />
if ( httpCode != 200 ) {<br />
error = true;<br />
// warn = true;<br />
}<br />
if (dbg_serial) {<br />
Serial.println("requesting: " + post_request);<br />
Serial.println("HTTP Status: " + httpCode );<br />
String response = https.getString();<br />
response.trim();//I get a leading linebreak, therefore trim the results (removes leading and trailing whitespaces)<br />
<br />
Serial.println("response: " + response ); //Print request response payload<br />
addr=response.c_str();<br />
}<br />
https.end(); //close connection<br />
return httpCode;<br />
}<br />
<br />
<br />
boolean isInteger(String str) {<br />
for (byte i = 0; i < str.length(); i++)<br />
{<br />
Serial.println("char " + String(i) + ": " + String(str.charAt(i)));<br />
if (!isDigit(str.charAt(i))) return false;<br />
}<br />
return true;<br />
}<br />
<br />
</source><br />
<br />
<br />
Database structure:<br />
<br />
<source lang="bash"><br />
Current database: innenklima<br />
<br />
mysql> show tables;<br />
+----------------------+<br />
| Tables_in_innenklima |<br />
+----------------------+<br />
| Bad |<br />
| Dachboden |<br />
| Gaestezimmer |<br />
...<br />
+----------------------+<br />
12 rows in set (0,01 sec)<br />
<br />
mysql> describe Bad;<br />
+-------------+-------+------+-----+---------+-------+<br />
| Field | Type | Null | Key | Default | Extra |<br />
+-------------+-------+------+-----+---------+-------+<br />
| timestamp | int | NO | PRI | NULL | |<br />
| temperature | float | YES | | NULL | |<br />
| humidity | float | YES | | NULL | |<br />
| abshumidity | float | YES | | NULL | |<br />
+-------------+-------+------+-----+---------+-------+<br />
4 rows in set (0,05 sec)<br />
<br />
<br />
</source><br />
<br />
<br />
webserver files:<br />
<br />
<br />
sensoren.php<br />
<source lang="PHP"><br />
<?php<br />
require_once __DIR__ . '/dicts.php';<br />
<br />
#for t_rh.php<br />
function nameFromID($id){<br />
return $names[$id];<br />
}<br />
<br />
function readNextId(){<br />
$filename = 'next.txt';<br />
return intval(file_get_contents($filename));<br />
}<br />
<br />
function incrementId($id,$addr){<br />
$filename = 'next.txt';<br />
$f = fopen($filename, 'w');<br />
<br />
if($addr[$id]=="end" or count($addr)<=($id)){<br />
$n=1;<br />
}else{<br />
$n=$id+1;<br />
}<br />
fwrite($f,$n);<br />
fclose($f);<br />
}<br />
<br />
<br />
#for ESP32 https call<br />
if($_POST["type"]=="addr"){<br />
$id=readNextId();<br />
echo ($addr[$id]);<br />
incrementId($id,$addr);<br />
}else{<br />
echo($names[$_GET["id"]]);<br />
echo "<br>";<br />
echo($addr[$_GET["id"]]);<br />
}<br />
?><br />
<br />
</source><br />
<br />
dicts.php:<br />
<br />
<source lang="PHP"><br />
<?php<br />
<br />
$names=array(<br />
1=>"Dachboden",<br />
2=>"Wintergarten",<br />
3=>"Bad",<br />
4=>"Wohnzimmer",<br />
5=>"Gaestezimmer",<br />
6=>"Naehzimmer",<br />
7=>"Schlafzimmer",<br />
8=>"Waschkueche",<br />
9=>"Kueche",<br />
10=>"KuecheUnten",<br />
11=>"Garage",<br />
12=>"end"<br />
<br />
);<br />
<br />
$addr=array(<br />
1=>"A4:C1:38:EB:2C:14", <br />
2=>"A4:C1:38:FF:28:B4",<br />
3=>"A4:C1:38:2A:CE:FE",<br />
4=>"A4:C1:38:B1:21:FD",<br />
5=>"A4:C1:38:98:C1:16",<br />
6=>"A4:C1:38:CE:B6:5D",<br />
7=>"A4:C1:38:B6:80:4C",<br />
8=>"A4:C1:38:5E:55:5E",<br />
9=>"A4:C1:38:09:5C:AF",<br />
10=>"A4:C1:38:AE:ED:3C",<br />
11=>"A4:C1:38:0D:0B:54",<br />
12=>"end"<br />
);<br />
<br />
#for t_rh.php<br />
<br />
<br />
<br />
<br />
<br />
#for ESP32 https call<br />
if($_POST["type"]=="addr"){<br />
echo ($addr[$_POST["id"]]);<br />
}else{<br />
#echo($names[$_GET["id"]]);<br />
#echo "<br>";<br />
#echo($addr[$_GET["id"]]);<br />
}<br />
?><br />
</source><br />
<br />
abshum.php:<br />
<br />
<source lang="PHP"><br />
<br />
<?php<br />
<br />
function saturationpressure($T){<br />
return 611.2*exp(17.62*$T/(243.12+$T));//in Pascal. T in °C<br />
}<br />
<br />
<br />
function abshum($rh, $T){<br />
<br />
$gasconst=8.314462618;//J/mol/K<br />
$molweight=18.01528;//g/mol<br />
<br />
<br />
$vaporpressure=$rh/100.0*saturationpressure($T);<br />
$abshum=$molweight/$gasconst*$vaporpressure/($T+273.15);<br />
<br />
return ($abshum);//g/m³<br />
}<br />
?><br />
</source><br />
<br />
t_rh.php:<br />
<source lang="PHP"><br />
<?php<br />
<br />
function createTable($sensorname){<br />
$statement = "CREATE TABLE IF NOT EXISTS ".$sensorname." (timestamp int NOT NULL, temperature float, humidity float, abshumidity float, PRIMARY KEY (timestamp));";<br />
execSQL($statement);<br />
}<br />
<br />
require_once("abshum.php");<br />
<br />
function insertValues($sensorname, $timestamp, $temperature, $humidity){<br />
if($temperature < -988888888 ){<br />
return;<br />
}<br />
$statement = "INSERT INTO ".$sensorname." (timestamp, temperature, humidity, abshumidity) VALUES (".$timestamp.", ".$temperature.", ".$humidity.", ".abshum($humidity,$temperature).");";<br />
execSQL($statement);<br />
}<br />
<br />
function execSQL($statement){<br />
$mysqli= new mysqli("host", "user", "password", "DB");<br />
$result=$mysqli->query($statement);<br />
}<br />
<br />
<br />
$tstamp=time();<br />
require_once __DIR__ . '/dicts.php';<br />
$filename = 'next.txt';<br />
$id=intval(file_get_contents($filename));<br />
$sensorname=$names[$id-1];<br />
if($sensorname != "end"){<br />
createTable($sensorname);<br />
insertValues($sensorname, $tstamp, $_POST["t"], $_POST["rh"]);<br />
}<br />
#echo($_POST["rh"]);<br />
#echo($_POST["addr"]);<br />
?><br />
</source><br />
<br />
tsleep.php:<br />
<source lang="PHP"><br />
<br />
<?php<br />
#minutes<br />
echo (15);<br />
?><br />
<br />
<br />
</source></div>
Gabriel