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