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);
?>