This commit is contained in:
Flo
2026-05-07 08:51:32 +02:00
parent 210bf06952
commit 604c8a3eaf
10 changed files with 153 additions and 192 deletions
+1
View File
@@ -3,3 +3,4 @@
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
.vscode/ipch .vscode/ipch
.aider*
-83
View File
@@ -1,83 +0,0 @@
/*
* DataSender.cpp
*
* Created on: 08.10.2022
* Author: flori
*/
#include "main.h"
#include "MyWifiClient.h"
#include "Seconds.h"
#include "DataSender.h"
DataSender dataSender;
#define SEND_INTERVAL_SECONDS 120
#define DATA_SIZE_PER_FENSTER 11
static uint8_t buf[DATA_SIZE_PER_FENSTER * NUM_FENSTER];
DataSender::DataSender()
{
bRequestSendWifi = true;
tNextSend = SEND_INTERVAL_SECONDS;
}
DataSender::~DataSender()
{
// TODO Auto-generated destructor stub
}
/**
*
*/
void DataSender::onSetup(void)
{
myWifiClient.onSetup();
}
/**
*
*/
void DataSender::onLoop(void)
{
if (Seconds::Get() >= tNextSend )
{
bRequestSendWifi = true;
}
if (bRequestSendWifi && myWifiClient.canSend())
{
bRequestSendWifi = false;
for (uint8_t i = 0; i < NUM_FENSTER; i++)
{
uint8_t offset = DATA_SIZE_PER_FENSTER * i;
memcpy( &buf[offset], alleFenster[i]->name, 8 );
uint16_t remainingTime = (uint16_t) alleFenster[i]->GetRemainingTime();
memcpy( &buf[offset+8], &remainingTime , 2);
uint8_t state = alleFenster[i]->IsOpen() ? 1 : 0;
state |= alleFenster[i]->ShallPiep() ? 2 : 0;
memcpy( &buf[offset+10], &state , 1);
}
myWifiClient.send(buf, sizeof(buf));
tNextSend = Seconds::Get() + SEND_INTERVAL_SECONDS;
}
myWifiClient.onLoop();
}
/**
*
*/
void DataSender::requestSend(void)
{
bRequestSendWifi = true;
}
-27
View File
@@ -1,27 +0,0 @@
/*
* DataSender.h
*
* Created on: 08.10.2022
* Author: flori
*/
#ifndef DATASENDER_H_
#define DATASENDER_H_
class DataSender
{
public:
DataSender();
virtual ~DataSender();
void onSetup(void);
void onLoop(void);
void requestSend(void);
private:
bool bRequestSendWifi;
uint32_t tNextSend;
};
extern DataSender dataSender;
#endif /* DATASENDER_H_ */
+31 -13
View File
@@ -5,6 +5,7 @@
*/ */
#include <WiFi.h> #include <WiFi.h>
#include <time.h>
#include "MyMqttClient.h" #include "MyMqttClient.h"
#include "Version.h" #include "Version.h"
@@ -14,12 +15,12 @@
MyMqttClient myMqttClient; MyMqttClient myMqttClient;
MyMqttClient::MyMqttClient() MyMqttClient::MyMqttClient()
: mqttClient(wifiClient) : pubSubClient(wifiClient)
, lastConnectAttemptMs(0) , lastConnectAttemptMs(0)
, lastWifiReconnectMs(0) , lastWifiReconnectMs(0)
{ {
mqttClient.setServer(MQTT_BROKER_IP, MQTT_BROKER_PORT); pubSubClient.setServer(MQTT_BROKER_IP, MQTT_BROKER_PORT);
mqttClient.setKeepAlive(300); pubSubClient.setKeepAlive(600);
} }
/** /**
@@ -29,7 +30,7 @@ MyMqttClient::MyMqttClient()
*/ */
bool MyMqttClient::ensureConnected() bool MyMqttClient::ensureConnected()
{ {
if (mqttClient.connected()) if (pubSubClient.connected())
{ {
return true; return true;
} }
@@ -51,22 +52,24 @@ bool MyMqttClient::ensureConnected()
bool ok; bool ok;
if (strlen(MQTT_USER) > 0) if (strlen(MQTT_USER) > 0)
{ {
ok = mqttClient.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD); ok = pubSubClient.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD,
MQTT_TEMP_RH, 0, true, "{\"T\":0,\"rh\":0,\"t\":0}");
} }
else else
{ {
ok = mqttClient.connect(MQTT_CLIENT_ID); ok = pubSubClient.connect(MQTT_CLIENT_ID, nullptr, nullptr,
MQTT_TEMP_RH, 0, true, "{\"T\":0,\"rh\":0,\"t\":0}");
} }
if (ok) if (ok)
{ {
Serial.println("[MQTT] Connected"); Serial.println("[MQTT] Connected");
mqttClient.publish(MQTT_TOPIC_STATUS, pubSubClient.publish(MQTT_TOPIC_SYSTEM,
"{\"e\":\"hello\",\"client\":\"" MQTT_CLIENT_ID VERSION_STR "\"}"); "{\"e\":\"hello\",\"client\":\"" MQTT_CLIENT_ID VERSION_STR "\"}");
} }
else else
{ {
Serial.printf("[MQTT] Connect failed, rc=%d\n", mqttClient.state()); Serial.printf("[MQTT] Connect failed, rc=%d\n", pubSubClient.state());
} }
return ok; return ok;
@@ -75,13 +78,28 @@ bool MyMqttClient::ensureConnected()
/** /**
* Publishes an arbitrary status payload to MQTT_TOPIC_STATUS. * Publishes an arbitrary status payload to MQTT_TOPIC_STATUS.
*/ */
void MyMqttClient::publishStatus(const char* payload) void MyMqttClient::publishStatus(const char* payload, bool retain)
{ {
if (!ensureConnected()) if (!ensureConnected())
{ {
return; return;
} }
mqttClient.publish(MQTT_TOPIC_STATUS , payload); pubSubClient.publish(MQTT_TOPIC_STATUS, payload, retain);
}
/**
* Publishes temperature and humidity data to MQTT_TEMP_RH topic.
*/
void MyMqttClient::publishTemperatureAndHumidity(int temperature, uint8_t humidity, uint32_t rawData)
{
if (!ensureConnected())
{
return;
}
char payload[80];
snprintf(payload, sizeof(payload),
"{\"T\":%d,\"rh\":%u,\"t\":%lu, \"raw\":%lu}", temperature, humidity, (unsigned long)time(nullptr), (unsigned long)rawData);
pubSubClient.publish(MQTT_TEMP_RH, payload, true);
} }
/** /**
@@ -104,18 +122,18 @@ void MyMqttClient::onLoop()
if (WiFi.isConnected()) if (WiFi.isConnected())
{ {
ensureConnected(); ensureConnected();
mqttClient.loop(); pubSubClient.loop();
static uint32_t tNextRssiMs = 0u; static uint32_t tNextRssiMs = 0u;
if (millis() >= tNextRssiMs) if (millis() >= tNextRssiMs)
{ {
tNextRssiMs = millis() + 600000u; tNextRssiMs = millis() + 600000u;
if (mqttClient.connected()) if (pubSubClient.connected())
{ {
char payload[48]; char payload[48];
snprintf(payload, sizeof(payload), snprintf(payload, sizeof(payload),
"{\"rssi\":%d }", (int)WiFi.RSSI()); "{\"rssi\":%d }", (int)WiFi.RSSI());
mqttClient.publish(MQTT_TOPIC_RSSI, payload); pubSubClient.publish(MQTT_TOPIC_RSSI, payload);
} }
} }
} }
+6 -2
View File
@@ -16,8 +16,10 @@
#define MQTT_BROKER_IP "flokke.de" #define MQTT_BROKER_IP "flokke.de"
#define MQTT_BROKER_PORT 1883 #define MQTT_BROKER_PORT 1883
#define MQTT_CLIENT_ID "Fensterpiepser" PROJECT_VARIANT #define MQTT_CLIENT_ID "Fensterpiepser" PROJECT_VARIANT
#define MQTT_TOPIC_SYSTEM "fenster/system/" PROJECT_VARIANT
#define MQTT_TOPIC_STATUS "fenster/status/" PROJECT_VARIANT #define MQTT_TOPIC_STATUS "fenster/status/" PROJECT_VARIANT
#define MQTT_TOPIC_RSSI "fenster/rssi/" PROJECT_VARIANT #define MQTT_TOPIC_RSSI "fenster/rssi/" PROJECT_VARIANT
#define MQTT_TEMP_RH "fenster/temprh/" PROJECT_VARIANT
// Optional: set to "" if no authentication required // Optional: set to "" if no authentication required
#define MQTT_USER "lightcontrol" #define MQTT_USER "lightcontrol"
#define MQTT_PASSWORD "mR9o3OYpAzUZvS" #define MQTT_PASSWORD "mR9o3OYpAzUZvS"
@@ -27,7 +29,7 @@ class MyMqttClient
{ {
private: private:
WiFiClient wifiClient; WiFiClient wifiClient;
PubSubClient mqttClient; PubSubClient pubSubClient;
uint32_t lastConnectAttemptMs; uint32_t lastConnectAttemptMs;
uint32_t lastWifiReconnectMs; uint32_t lastWifiReconnectMs;
@@ -38,7 +40,9 @@ public:
MyMqttClient(); MyMqttClient();
void onLoop(); void onLoop();
void publishStatus(const char* payload); void publishStatus(const char* payload, bool retain = false);
void publishTemperatureAndHumidity(int temperature, uint8_t humidity, uint32_t rawData);
void closeConnection() { pubSubClient.disconnect(); }
}; };
extern MyMqttClient myMqttClient; extern MyMqttClient myMqttClient;
+66 -48
View File
@@ -5,12 +5,12 @@
* Author: flori * Author: flori
*/ */
#include "main.h" #include "main.h"
#include "DataSender.h"
#include "ReceiverFunkThermometer.h" #include "ReceiverFunkThermometer.h"
#include <MyMqttClient.h>
#define DEBUG_LEVEL 0 #define DEBUG_LEVEL 2
#define MonitorPrint(x) // Serial.print(x) #define MonitorPrint(x) Serial.print(x)
ReceiverFunkThermometer receiverThermo; ReceiverFunkThermometer receiverThermo;
@@ -57,11 +57,11 @@ IRAM_ATTR void ReceiverFunkThermometer::Isr(uint32_t dtMicros, bool pinValue)
SignalDurationThermometer_t thisDuration = FUNK_THERMO_INVALID; SignalDurationThermometer_t thisDuration = FUNK_THERMO_INVALID;
if (dtMicros > 350 && dtMicros < 600) if (dtMicros > 400 && dtMicros < 600)
{ {
thisDuration = MS_0_5; thisDuration = MS_0_5;
} }
else if (dtMicros > 800 && dtMicros < 1200) else if (dtMicros > 900 && dtMicros < 1100)
{ {
thisDuration = MS_1_0; thisDuration = MS_1_0;
} }
@@ -89,23 +89,9 @@ IRAM_ATTR void ReceiverFunkThermometer::Isr(uint32_t dtMicros, bool pinValue)
} }
else if (pinValue == HIGH ) else if (pinValue == HIGH )
{ {
#if DEBUG_LEVEL > 1
bool bprint = (rByteIndex > 0 || rBitIndex<7);
#else
bool bprint = false;
#endif
if (bprint)
{
sprintf(textBuf, "\n%d %d : ", rByteIndex, rBitIndex );
MonitorPrint(textBuf);
}
if (thisDuration==MS_2_0 && lastDuration == MS_0_5) if (thisDuration==MS_2_0 && lastDuration == MS_0_5)
{ {
if (bprint)
{
MonitorPrint(F("1"));
}
/* bit 1 received */ /* bit 1 received */
rBytes[rByteIndex] |= (1 << rBitIndex); rBytes[rByteIndex] |= (1 << rBitIndex);
if (rBitIndex == 0) if (rBitIndex == 0)
@@ -126,10 +112,6 @@ IRAM_ATTR void ReceiverFunkThermometer::Isr(uint32_t dtMicros, bool pinValue)
} }
else if (thisDuration==MS_1_0 &&lastDuration == MS_0_5) else if (thisDuration==MS_1_0 &&lastDuration == MS_0_5)
{ {
if (bprint)
{
MonitorPrint(F("0"));
}
/* bit 0 received */ /* bit 0 received */
if (rBitIndex == 0) if (rBitIndex == 0)
{ {
@@ -147,14 +129,9 @@ IRAM_ATTR void ReceiverFunkThermometer::Isr(uint32_t dtMicros, bool pinValue)
rBytes[0] = 0; rBytes[0] = 0;
} }
} }
} }
} }
lastDuration = thisDuration; lastDuration = thisDuration;
} }
/** /**
@@ -247,8 +224,53 @@ bytes received from woolworth temp
69 69
6
111
93
102
10
96
6
111
93
102
10
* *
*/ */
IRAM_ATTR void ReceiverFunkThermometer::printBits(void)
{
Serial.println("");
Serial.println("T_RH");
for (int i = 0; i < THERMO_KEY_NUMBYTES_PER_KEY; i++)
{
for (int j = 7; j >= 0; j--)
{
Serial.print((rBytes[i] >> j) & 0x01);
}
Serial.print(" ");
}
}
/*
Fehler: (anderer Sensor?)
01100000 00000110 10011111 01011101 T_RH
01100000 00000110 10011111 01011101 105 / 93
Korrekt:
01011000 00000111 10001111 00110110 T_RH
01011000 00000111 10001111 00110110 120 / 54
iiiiiiii tttttttt ttttffff hhhhhhhh
*/
IRAM_ATTR void ReceiverFunkThermometer::OnTempReceived(void) IRAM_ATTR void ReceiverFunkThermometer::OnTempReceived(void)
{ {
@@ -258,24 +280,13 @@ IRAM_ATTR void ReceiverFunkThermometer::OnTempReceived(void)
value : id id t t t 0xf h h value : id id t t t 0xf h h
*/ */
#define PRINT_ON_TEMP_RECEIVED 0 #define PRINT_ON_TEMP_RECEIVED 0
#if 0
/* testdaten */
rBytes[0] = 112u;
rBytes[1] = 255u;
rBytes[2] = 191u;
rBytes[3] = 89u;
#endif
#if PRINT_ON_TEMP_RECEIVED #if PRINT_ON_TEMP_RECEIVED
Serial.println(rBytes[0]); printBits();
Serial.println(rBytes[1]);
Serial.println(rBytes[2]);
Serial.println(rBytes[3]);
#endif #endif
if ((rBytes[2]&0xF) == 0xF) /* these 4 bits must be 1 */ if ( ((rBytes[0]&0xF0)==0x50) /* id bits are 0101 */
&& (rBytes[2]&0xF) == 0xF)
{ {
int16_t tempInt = 0; int16_t tempInt = 0;
int16_t tempNow = 0; int16_t tempNow = 0;
uint8_t rhNow = rBytes[3]; uint8_t rhNow = rBytes[3];
@@ -291,20 +302,17 @@ IRAM_ATTR void ReceiverFunkThermometer::OnTempReceived(void)
tempInt = (~tempInt) & 0xFFFu; tempInt = (~tempInt) & 0xFFFu;
tempInt += 1; tempInt += 1;
} }
#if PRINT_ON_TEMP_RECEIVED
Serial.println(tempInt);
#endif
/* do the rounding with positive number */ /* do the rounding with positive number */
tempNow = (tempInt + 5) / 10; tempNow = (tempInt + 5) / 10;
dataLast.tempDeciCelsius = tempInt;
if (isNegative) if (isNegative)
{ {
/* set to negative */ /* set to negative */
tempNow = -tempNow; tempNow = -tempNow;
dataLast.tempDeciCelsius = -dataLast.tempDeciCelsius;
} }
#if PRINT_ON_TEMP_RECEIVED
Serial.println(tempNow);
#endif
int16_t dTempAbs = (tempNow >= dataLast.tempC) ? (tempNow - dataLast.tempC) : (dataLast.tempC - tempNow); int16_t dTempAbs = (tempNow >= dataLast.tempC) ? (tempNow - dataLast.tempC) : (dataLast.tempC - tempNow);
uint8_t dRHAbs = (rhNow >= dataLast.rhPercent) ? (rhNow - dataLast.rhPercent) : (dataLast.rhPercent - rhNow); uint8_t dRHAbs = (rhNow >= dataLast.rhPercent) ? (rhNow - dataLast.rhPercent) : (dataLast.rhPercent - rhNow);
@@ -316,9 +324,19 @@ IRAM_ATTR void ReceiverFunkThermometer::OnTempReceived(void)
if ( (dTempAbs <= 2) && if ( (dTempAbs <= 2) &&
(dRHAbs <= 2u) ) (dRHAbs <= 2u) )
#endif #endif
{
if (data.tempDeciCelsius != dataLast.tempDeciCelsius || data.rhPercent != dataLast.rhPercent)
{ {
bNewData = true; bNewData = true;
data = dataLast; data = dataLast;
data.rawData = ((uint32_t)rBytes[0] << 24) | ((uint32_t)rBytes[1] << 16) | ((uint32_t)rBytes[2] << 8) | rBytes[3];
#if PRINT_ON_TEMP_RECEIVED
Serial.print(data.tempDeciCelsius);
Serial.print(" / ");
Serial.println(data.rhPercent);
#endif
}
} }
} }
+3 -1
View File
@@ -23,8 +23,10 @@ typedef enum
typedef struct typedef struct
{ {
int16_t tempDeciCelsius;
int16_t tempC; int16_t tempC;
uint8_t rhPercent; uint8_t rhPercent;
uint32_t rawData;
} ReceiverFunkThermometerData_t; } ReceiverFunkThermometerData_t;
@@ -45,7 +47,7 @@ private:
void OnTempReceived(void); void OnTempReceived(void);
void ResetBuffer(void); void ResetBuffer(void);
void NextByte(void); void NextByte(void);
void printBits(void);
uint8_t rBytes[THERMO_KEY_NUMBYTES_PER_KEY]; uint8_t rBytes[THERMO_KEY_NUMBYTES_PER_KEY];
uint8_t rByteIndex = 0; uint8_t rByteIndex = 0;
-1
View File
@@ -76,7 +76,6 @@ void UpdateHandler()
{ {
webServer.sendHeader("Connection", "close"); webServer.sendHeader("Connection", "close");
webServer.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); webServer.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
myMqttClient.publishStatus("{\"event\":\"reset_update\", \"variant\": \"" PROJECT_VARIANT "\" }");
ESP.restart(); ESP.restart();
}, []() }, []()
{ {
+1 -1
View File
@@ -17,7 +17,7 @@
#endif #endif
#define PROJECT_NAME "FENSTER_PIEPSER_NODEMCU_32_S_" PROJECT_VARIANT #define PROJECT_NAME "FENSTER_PIEPSER_NODEMCU_32_S_" PROJECT_VARIANT
#define VERSION_STR "_v2.0.3" #define VERSION_STR "_v2.0.8"
#endif /* VERSION_H_ */ #endif /* VERSION_H_ */
+42 -13
View File
@@ -11,7 +11,6 @@
#include "Display.h" #include "Display.h"
#include "Display_SSD1306.h" #include "Display_SSD1306.h"
#include "Seconds.h" #include "Seconds.h"
#include "DataSender.h"
#include "InterruptHandler.h" #include "InterruptHandler.h"
#include "xcp/XcpPort.h" #include "xcp/XcpPort.h"
#include "UpdateHandler.h" #include "UpdateHandler.h"
@@ -61,9 +60,10 @@
#define TONE_FREQUENCY_HZ 2000 #define TONE_FREQUENCY_HZ 2000
#define TIMEOUT_WIFI_CONNECTION_MS 30000u
#define USE_XCP (1u) #define USE_XCP (1u)
#define USE_WIFI (1u) /* WARNING, no OTA update without wifi ! */ #define USE_WIFI (1u) /* WARNING, no OTA update without wifi ! */
#define USE_DATASENDER (0u)
/*---------------- GLOBAL VARIABLES ------------- */ /*---------------- GLOBAL VARIABLES ------------- */
uint32_t gtMillis; uint32_t gtMillis;
@@ -156,7 +156,7 @@ static void handleDispUpdate(void);
static void handleKeyReceived(void); static void handleKeyReceived(void);
static void updateIsNighttime(); static void updateIsNighttime();
static void updatePiepPattern(void); static void updatePiepPattern(void);
static void handleWifiConnection(void);
/** /**
* *
@@ -174,8 +174,6 @@ void setup()
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(ssidElektro, password); WiFi.begin(ssidElektro, password);
dataSender.onSetup();
const char* ntpServer = "ptbtime3.ptb.de"; const char* ntpServer = "ptbtime3.ptb.de";
const long gmtOffset_sec = 3600; const long gmtOffset_sec = 3600;
const int daylightOffset_sec = 3600; const int daylightOffset_sec = 3600;
@@ -254,11 +252,7 @@ void loop()
#if USE_WIFI #if USE_WIFI
//updateIsNighttime(); //updateIsNighttime();
handleWifiConnection();
#if USE_DATASENDER
dataSender.onLoop();
#endif
myMqttClient.onLoop(); myMqttClient.onLoop();
UpdateHandler(); UpdateHandler();
#endif #endif
@@ -280,6 +274,40 @@ void loop()
loopCountSincePause++; loopCountSincePause++;
} }
/* don't call from interrupt, set gbRestartRequest to true instead */
static void myEspRestart()
{
myMqttClient.closeConnection();
delay(100);
esp_restart();
}
/**
*
*/
static void handleWifiConnection(void)
{
static uint32_t tDoSoftResetMs = 0;
if (true == WiFi.isConnected())
{
tDoSoftResetMs = 0;
}
else
{
if (tDoSoftResetMs == 0u)
{
tDoSoftResetMs = millis() + TIMEOUT_WIFI_CONNECTION_MS;
WiFi.reconnect();
}
else if (millis() > tDoSoftResetMs)
{
myMqttClient.publishStatus("{\"reset\":\"reset due to WiFi connection timeout\"}");
myEspRestart();
}
}
}
static void handleDispUpdate(void) static void handleDispUpdate(void)
{ {
/* cyclically request display update */ /* cyclically request display update */
@@ -443,6 +471,8 @@ static void handleKeyReceived(void)
/* update wait time according to temperature */ /* update wait time according to temperature */
updateWaittime(); updateWaittime();
myMqttClient.publishTemperatureAndHumidity(thermoData.tempC, thermoData.rhPercent, thermoData.rawData);
} }
@@ -460,7 +490,6 @@ static void handleKeyReceived(void)
if (bWindowChanged) if (bWindowChanged)
{ {
bUpdateDisp = true; bUpdateDisp = true;
dataSender.requestSend();
bRequestShortBeep = true; bRequestShortBeep = true;
publishAllFensterStatus("move"); publishAllFensterStatus("move");
if (lastKeyDirection == DIRECTION_CLOSE) if (lastKeyDirection == DIRECTION_CLOSE)
@@ -520,7 +549,7 @@ static void testWaitTime()
static void publishAllFensterStatus(const char *event) static void publishAllFensterStatus(const char *event)
{ {
char payload[256]; char payload[256];
sprintf(payload, "{ \"e\": \"%s\", \"n\": %d, \"f\": [", event, NUM_FENSTER); sprintf(payload, "{ \"t\": %lu, \"e\": \"%s\", \"n\": %d, \"f\": [", (unsigned long)time(nullptr), event, NUM_FENSTER);
for (uint8_t i = 0; i < NUM_FENSTER; i++) for (uint8_t i = 0; i < NUM_FENSTER; i++)
{ {
if (i>0) strcat(payload, ","); if (i>0) strcat(payload, ",");
@@ -542,7 +571,7 @@ static void publishAllFensterStatus(const char *event)
} }
strcat(payload, "] }"); strcat(payload, "] }");
myMqttClient.publishStatus(payload); myMqttClient.publishStatus(payload, true);
} }
/** /**