Ziel war es, mit überschaubarem Aufwand einen relativ frei positionierbaren Enocean Empfänger zu erhalten, der die empfangenen Enocean Telegramme ohne großes Tamtam zum MQTT Broker überträgt. Dort kümmert sich dann z.B. Node Red um die Verarbeitung. Damit lassen sich recht schlank die netten batterielosen Taster und Fenstergriffe in die Homeautomation einbinden. Aber insbesondere auch die Sensoren, die manchmal aufgrund von Aufbau- und Einbausituation nur wenige Meter Reichweite erreichen. Da reicht es bei mir nicht immer bis zur Zentrale mit dem USB Enocean Empfänger.
Zum Einsatz kommen ein ESP32 C6 Module (vielleicht nutze ich ja irgendwann auch noch die Zigbee und Thread Fähigkeiten diese Moduls) und ein Enocean TCM 320 Modul (ca. 20 €).
Der Aufbau ist recht trivial, das Enocean Modul wird vom ESP Board mit 3,3V versorgt und da ich nur empfangen will, gibt es lediglich eine Verbindung zwischen Enocean TX zu ESP RX UART. 9600 Baud, 8N1. Das war es schon. Das Enocean Modul braucht eine Brücke zwischen GND und dem ersten benachbarten IO Pin, um in den einfachen Empfänger-Modus zu gehen, bei dem alle empfangenen Enocean Telegramme ungefiltert über den UART TX ausgegeben werden.
Der sicherlich noch verbesserungsfähige Arduino Sketch ist angefügt. Läuft schon und erfüllt für meine Zwecke seinen Dienst.
Ich hoffe, den ein oder anderen lädt das zum Nachmachen und Verfeinern ein.
Die Telegramminhalte müssen noch gerätespezifisch ausgewertet werden. Im Falle der Taster und Fenstergriffe ist das recht schlicht. Man sieht ja, wie sich die verschiedenen Tasten oder Fenstergriff-Zustandswechsel im (bereits von Sender ID isoliertem) Telegramminhalt darstellen. Ich habe gegenwärtig leider keinen Zugriff auf weitere Enocean Sensoren, wie z.B. Wetterstation oder Temperaturregelung. Ich gehe aber davon aus, dass diese Telegramminhalte sich auch leicht decodieren lassen.
Die etwas aufwendige Konstruktion rührt daher, dass dieses Enocean Modul einen 2,0 mm statt üblichen 2,54 mm Pitch hat und ich erst annahm, ich müsste mehr Verbindungen herstellen. Daher habe ich eine 2,0 <-> 2,54 Adapterplatine besorgt. Das ist jedoch für die nur drei nötigen Verbindungen eher overkill.
#include <WiFi.h>
#include "wifi_secrets.h"
#include <PubSubClient.h>
#include <esp_wifi.h>
//const char* ssid = "***From wifi_secrets.h ***";
//const char* password = "***From wifi_secrets.h ***";
//The MQTT broker address
const char* mqtt_server = "192.168.30.40";
uint8_t baseMac[6];
char mac_str[13];
void readMacAddress(){
esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
if (ret == ESP_OK) {
Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
baseMac[0], baseMac[1], baseMac[2],
baseMac[3], baseMac[4], baseMac[5]);
} else {
Serial.println("Failed to read MAC address");
}
snprintf (mac_str, 13, "%02X%02X%02X%02X%02X%02X\n",
baseMac[0], baseMac[1], baseMac[2],
baseMac[3], baseMac[4], baseMac[5]);
}
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
//WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, HIGH);
} else {
digitalWrite(BUILTIN_LED, LOW);
}
}
String clientId = "ESP32C6Client-";
void reconnect() {
if (WiFi.status() != WL_CONNECTED)
{
Serial.print("Lost WiFi, trying to reconnect ...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
}
while (!client.connected()) {
Serial.printf("RSSI: %d dBm\n", WiFi.RSSI());
Serial.print("Attempting MQTT connection...");
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
//client.publish("eocean/hardbeat", "thump thump");
// ... and resubscribe
client.subscribe("inTopic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup() {
clientId += String(random(0xffff), HEX);
pinMode(BUILTIN_LED, OUTPUT);
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
readMacAddress();
//Start UART for the Enocean module TCM320
Serial1.begin(9600, SERIAL_8N1, 12, 13);
if(Serial1)
{
Serial.println("Serial1 successfully set up");
}
}
char serial_buf[100];
int serial_buf_end = 0;
int serial_buf_ts = 0;
int sync_byte = 0;
unsigned long now = 0;
int target_length = 99;
int enocean_telegram_ready = 0;
void check_seriellen_empfang()
{
while (Serial1.available())
{
now = millis();
char aktuellesZeichen = (char)Serial1.read();
if ((now - serial_buf_ts) > 15) //Timeout for receiving complete telegram
{
serial_buf_end = 0;
sync_byte = 0;
serial_buf_ts = now;
target_length = 99;
enocean_telegram_ready = 0;
}
if ((sync_byte == 0) && (aktuellesZeichen == 0xa5))
{
sync_byte = 1;
serial_buf_ts = now;
}
if ((sync_byte == 2) && (serial_buf_end < (target_length + 3)) && (serial_buf_end < 99))
{
if (serial_buf_end == 2)
{
target_length = (aktuellesZeichen & 31);
enocean_telegram_ready = 0;
}
serial_buf[serial_buf_end] = aktuellesZeichen;
serial_buf_end++;
serial_buf_ts = now;
}
if ((sync_byte == 1) && (aktuellesZeichen == 0x5a))
{
sync_byte = 2;
serial_buf[0] = 0xa5;
serial_buf[1] = 0x5a;
serial_buf_end = 2;
serial_buf_ts = now;
target_length = 99;
enocean_telegram_ready = 0;
serial_buf_ts = now;
}
if (serial_buf_end == (target_length + 3))
{
enocean_telegram_ready = serial_buf_end;
Serial.print("Enocean telegram: ");
for(int i = 0; i < serial_buf_end; i++)
{
if(serial_buf[i] < 0xa)
{
Serial.print("0");
Serial.print(serial_buf[i],HEX);
}
else
{
Serial.print(serial_buf[i],HEX);
}
Serial.print(" ");
}
Serial.println("");
}
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
check_seriellen_empfang();
now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
char temp_str[100];
snprintf (msg, MSG_BUFFER_SIZE, "thump thump #%ld", value);
Serial.printf("RSSI: %d dBm\n", WiFi.RSSI());
Serial.print("Publish message: ");
Serial.println(msg);
strcpy(temp_str,"enocean/heartbeat/");
strcat(temp_str, mac_str);
client.publish(temp_str, msg);
}
if(enocean_telegram_ready > 0) //enocean_telegram_ready contains the telegram length
{
// ********** publish the whole raw telegram received by the Enocean module
char temp_str[100];
strcpy(temp_str,"enocean/raw/");
strcat(temp_str, mac_str);
Serial.println(temp_str);
client.publish(temp_str, (const uint8_t*) serial_buf, enocean_telegram_ready);
// ********** publish only the telegram data with the Enocean ID to identify the source | to distiguish different receivers (if you use more than one) the MAC adress of the ESP is added | the topic looks like this:
// "enocean/ID_FED2E7E4/404CCA47E49C" | you can pick it up without the MAC adress: "enocean/ID_FED2E7E4/#"
snprintf (temp_str, 20, "enocean/ID_%02X%02X%02X%02X",
serial_buf[enocean_telegram_ready-6], serial_buf[enocean_telegram_ready-5], serial_buf[enocean_telegram_ready-4],
serial_buf[enocean_telegram_ready-3]);
strcat(temp_str, "/");
strcat(temp_str, mac_str);
client.publish(temp_str, (const uint8_t*) serial_buf+4, enocean_telegram_ready-10);
enocean_telegram_ready = 0;
}
}
Die Enocean MQTT bridge stellt die Enocean Information in folgenden MQTT Topics zur Verfügung:
-
enocean/heartbeat/#
Alle 2 Sekunden ein Lebenszeichen der bridge. -
enocean/raw/404CCA47E49C (Beispiel)
Wobei 404CCA47E49C die MAC Adresse des ESP boards ist.
Dieses Topic reicht die vom Enocean TCM 320 Modul zur Verfügung gestellten Telegramminformationen einfach durch. Dieses topic ist unter anderem hilfreich, um neue Enocean Quellen zu identifizieren. Die MAC Adresse sorgt dafür, dass auch mehrere dieser Enocean MQTT bridges koexistieren können. Wenn nur eines betrieben wird oder nicht zwischen bridges unterschieden werden soll, sind die Telegramm Rohdaten einfach zu bekommen unter:
enocean/raw/# -
enocean/ID_FED2E7E4/404CCA47E49C (Beispiel)
Jede Enocean Quelle ereugt so ihr eigenes MQTT topic, dass den eigentlichen Telegramminhalt (bei TCM 320 immer 4 byte) bereinigt von Quelladresse, header usw. bereitstellt. ID_XXXXXXXX identifiziert die Telegrammquelle (also das Enocean Gerät) und 404CCA47E49C erneut die MAC Adresse der Enocean MQTT bridge, die meist wieder ignoriert werden kann durch:
enocean/ID_FED2E7E4/#
Hier noch drei Node Red function nodes, die die Telegrammdaten von einem (Jung) Enocean 2fach, 4fach Taster und einem (Eltaco) Enocean Fenstergriff auswerten (ich glaube, eigentlich steckt hier in allen Fällen Eltaco dahinter). Die Tasterauswertung wirkt etwas "groß" weil ich für jede der Tasten einmal den reinen gedrückt-Status, Erkennung kurzer Tastendruck, Status langer Tastendruck auswerte und über je einen Ausgang ausgebe.
[
{
"id": "e26dc31320f72492",
"type": "function",
"z": "cf80121d93fd6aa6",
"name": "Jung Enocean 4g button eval",
"func": "let wait_timer_return = context.get(\"wait_timer_return\") || 0;\nlet button_states = context.get(\"button_states\") || [0, 0, 0, 0]; //[bottom left, top left, br, tr]\nlet long_button_states = context.get(\"long_button_states\") || [0, 0, 0, 0]; //[bottom left, top left, br, tr]\n\nlet msg01 = {};\nlet msg02 = {};\nlet msg03 = {};\nlet msg04 = {};\nlet msg05 = {};\nlet msg06 = {};\nlet msg07 = {};\nlet msg08 = {};\nlet msg09 = {};\nlet msg10 = {};\nlet msg11 = {};\nlet msg12 = {};\nlet msg13 = {};\n\nmsg01.topic = \"b1_state\";\nmsg02.topic = \"b1_short\";\nmsg03.topic = \"b1_long\";\nmsg04.topic = \"b2_state\";\nmsg05.topic = \"b2_short\";\nmsg06.topic = \"b2_long\";\nmsg07.topic = \"b3_state\";\nmsg08.topic = \"b3_short\";\nmsg09.topic = \"b3_long\";\nmsg10.topic = \"b4_state\";\nmsg11.topic = \"b4_short\";\nmsg12.topic = \"b4_long\";\n\n/*\nmsg01.payload = x; // Switch status 1=pressed, 0=released;\nmsg02.payload = x; // 1=short press recognised\nmsg03.payload = x; // 1=long press recognised, 0=long press released\n*/\n\nif (msg.topic == \"timer_long_press_elapsed\") //Timer for long press detection elapsed\n{\n wait_timer_return = 0;\n context.set(\"wait_timer_return\", 0);\n\n //detect, if we wait for Longpress detection --> send long pressed event\n\n /// ****************** Start of long_button_state press section **********************\n {\n if (button_states[0] == 1) {\n msg01 = null;\n msg02 = null;\n msg03.payload = 1;\n long_button_states[0] = 1;\n }\n else\n {\n long_button_states[0] = 0;\n msg01 = null;\n msg02 = null;\n msg03 = null;\n }\n\n if (button_states[1] == 1) {\n msg04 = null;\n msg05 = null;\n msg06.payload = 1;\n long_button_states[1] = 1;\n }\n else\n {\n long_button_states[1] = 0;\n msg04 = null;\n msg05 = null;\n msg06 = null;\n }\n\n if (button_states[2] == 1) {\n msg07 = null;\n msg08 = null;\n msg09.payload = 1;\n long_button_states[2] = 1;\n }\n else {\n long_button_states[2] = 0;\n msg07 = null;\n msg08 = null;\n msg09 = null;\n }\n\n if (button_states[3] == 1) {\n msg10 = null;\n msg11 = null;\n msg12.payload = 1;\n long_button_states[3] = 1;\n }\n else {\n long_button_states[3] = 0;\n msg10 = null;\n msg11 = null;\n msg12 = null;\n }\n\n context.set(\"long_button_states\", long_button_states);\n\n msg13 = null;\n }\n /// ****************** End of of long_button_state press section **********************\n}\nelse\n{\n if (msg.payload[0] != 0) //some button pressed\n {\n wait_timer_return = 1;\n context.set(\"wait_timer_return\", 1);\n\n msg13.topic = \"timer_long_press_elapsed\";\n msg13.id = msg._msgid;\n\n //Which bottom is pressed:\n let button1 = msg.payload[0] & 0xF0;\n button1 = button1 >> 4;\n\n let button2 = msg.payload[0] & 0x0F;\n\n button_states[0] = 0;\n button_states[1] = 0;\n button_states[2] = 0;\n button_states[3] = 0;\n \n switch (button1)\n {\n case 1:\n button_states[0] = 1;\n msg01.payload = 1;\n msg02 = null;\n msg03 = null;\n break;\n case 3:\n button_states[1] = 1;\n msg04.payload = 1;\n msg05 = null;\n msg06 = null;\n break;\n case 5:\n button_states[2] = 1;\n msg07.payload = 1;\n msg08 = null;\n msg09 = null;\n break;\n case 7:\n button_states[3] = 1;\n msg10.payload = 1;\n msg11 = null;\n msg12 = null;\n break;\n }\n switch (button2) {\n case 1:\n button_states[0] = 1;\n msg01.payload = 1;\n msg02 = null;\n msg03 = null;\n break;\n case 3:\n button_states[1] = 1;\n msg04.payload = 1;\n msg05 = null;\n msg06 = null;\n break;\n case 5:\n button_states[2] = 1;\n msg07.payload = 1;\n msg08 = null;\n msg09 = null;\n break;\n case 7:\n button_states[3] = 1;\n msg10.payload = 1;\n msg11 = null;\n msg12 = null;\n break;\n }\n\n context.set(\"button_states\", button_states);\n \n if (button_states[0] == 0)\n {\n msg01 = null;\n msg02 = null;\n msg03 = null;\n }\n if (button_states[1] == 0)\n {\n msg04 = null;\n msg05 = null;\n msg06 = null;\n }\n if (button_states[2] == 0)\n {\n msg07 = null;\n msg08 = null;\n msg09 = null;\n }\n if (button_states[3] == 0)\n {\n msg10 = null;\n msg11 = null;\n msg12 = null;\n } \n }\n else //button released\n {\n msg13 = null;\n\n /// ****************** Start of button state section **********************\n {\n if (button_states[0] == 1)\n {\n msg01.payload = 0;\n }\n else\n {\n msg01 = null;\n }\n\n if (button_states[1] == 1) {\n msg04.payload = 0;\n }\n else {\n msg04 = null;\n }\n\n if (button_states[2] == 1) {\n msg07.payload = 0;\n }\n else {\n msg07 = null;\n }\n\n if (button_states[3] == 1) {\n msg10.payload = 0;\n }\n else {\n msg10 = null;\n }\n\n context.set(\"button_states\", [0, 0, 0, 0]);\n }\n /// ****************** End of button state section **********************\n\n /// ****************** Start of long_button_state release section **********************\n {\n if (long_button_states[0] == 1)\n {\n msg02 = null;\n msg03.payload = 0;\n msg05 = null;\n msg08 = null;\n msg11 = null;\n }\n else\n {\n msg03 = null;\n }\n\n if (long_button_states[1] == 1) {\n msg05 = null;\n msg06.payload = 0;\n msg02 = null;\n msg08 = null;\n msg11 = null;\n }\n else {\n msg06 = null;\n }\n\n if (long_button_states[2] == 1) {\n msg08 = null;\n msg09.payload = 0;\n msg02 = null;\n msg05 = null;\n msg11 = null;\n }\n else {\n msg09 = null;\n }\n\n if (long_button_states[3] == 1) {\n msg11 = null;\n msg12.payload = 0;\n msg02 = null;\n msg05 = null;\n msg08 = null;\n }\n else {\n msg12 = null;\n }\n\n context.set(\"long_button_states\", [0, 0, 0, 0]);\n }\n /// ****************** End of of long_button_state release section **********************\n\n /// ****************** Start of button short section **********************\n {\n if (wait_timer_return == 1)\n {\n if (button_states[0] == 1)\n {\n msg02.payload = 1;\n msg03 = null;\n }\n else\n {\n msg02 = null;\n }\n\n if (button_states[1] == 1) {\n msg05.payload = 1;\n msg06 = null;\n }\n else\n {\n msg05 = null;\n }\n\n if (button_states[2] == 1) {\n msg08.payload = 1;\n msg09 = null;\n }\n else\n {\n msg08 = null;\n }\n\n if (button_states[3] == 1) {\n msg11.payload = 1;\n msg12 = null;\n }\n else\n {\n msg11 = null;\n }\n }\n }\n /// ****************** Emd of button short section **********************\n\n wait_timer_return = 0;\n context.set(\"wait_timer_return\", 0);\n }\n}\n\n\nreturn [msg01, msg02, msg03, msg04, msg05, msg06, msg07, msg08, msg09, msg10, msg11, msg12, msg13];",
"outputs": 13,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 450,
"y": 360,
"wires": [
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[],
[
"64afd72459788ab7"
]
],
"outputLabels": [
"Button 1 (bl) status (pressed 1 / released 0)",
"Button 1 (bl) short press (1)",
"Button 1 (bl) long press (start 1 / end 0)",
"Button 2 (tl) status (pressed 1 / released 0)",
"Button 2 (tl) short press (1)",
"Button 2 (tl) long press (start 1 / end 0)",
"Button 3 (br) status (pressed 1 / released 0)",
"Button 3 (br) short press (1)",
"Button 3 (br) long press (start 1 / end 0)",
"Button 4 (tr) status (pressed 1 / released 0)",
"Button 4 (tr) short press (1)",
"Button 4 (tr) long press (start 1 / end 0)",
"Start timer for long button press recognition"
],
"icon": "font-awesome/fa-toggle-on"
},
{
"id": "ab85a5b440b8f359",
"type": "mqtt in",
"z": "cf80121d93fd6aa6",
"name": "Jung_rocker4gang_01",
"topic": "enocean/ID_XXXXXXXX/#",
"qos": "2",
"datatype": "auto-detect",
"broker": "9c9e7e65436a5109",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 120,
"y": 360,
"wires": [
[
"e26dc31320f72492"
]
]
},
{
"id": "64afd72459788ab7",
"type": "delay",
"z": "cf80121d93fd6aa6",
"name": "Longpress time",
"pauseType": "delay",
"timeout": "300",
"timeoutUnits": "milliseconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 443,
"y": 514,
"wires": [
[
"e26dc31320f72492"
]
]
},
{
"id": "73ae7d391b235aa7",
"type": "mqtt in",
"z": "cf80121d93fd6aa6",
"name": "Eltaco_window_handle_01",
"topic": "enocean/ID_XXXXXXXX/#",
"qos": "2",
"datatype": "auto-detect",
"broker": "9c9e7e65436a5109",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 130,
"y": 600,
"wires": [
[
"0de14ba6ece1060b"
]
]
},
{
"id": "0de14ba6ece1060b",
"type": "function",
"z": "cf80121d93fd6aa6",
"name": "Enocean window handle",
"func": "\nswitch (msg.payload[0])\n{\n case 0xc0:\n msg.payload = 1;\n break;\n case 0xe0:\n msg.payload = 1;\n break;\n case 0xf0:\n msg.payload = 2;\n break;\n case 0xd0:\n msg.payload = 0;\n break;\n default:\n msg.payload = 99;\n break;\n}\n\nreturn msg;",
"outputs": 1,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 450,
"y": 600,
"wires": [
[]
],
"outputLabels": [
"0 closed, 1 open, 2 tilted"
],
"icon": "font-awesome/fa-toggle-on"
},
{
"id": "58d6a49e79bd69e3",
"type": "mqtt in",
"z": "cf80121d93fd6aa6",
"name": "Jung_rocker2gang_02",
"topic": "enocean/ID_XXXXXXXX/#",
"qos": "2",
"datatype": "auto-detect",
"broker": "9c9e7e65436a5109",
"nl": false,
"rap": true,
"rh": 0,
"inputs": 0,
"x": 130,
"y": 100,
"wires": [
[
"93ac0df52d8e9698"
]
]
},
{
"id": "93ac0df52d8e9698",
"type": "function",
"z": "cf80121d93fd6aa6",
"name": "Jung Enocean 2g button eval",
"func": "let wait_timer_return = context.get(\"wait_timer_return\") || 0;\nlet button_states = context.get(\"button_states\") || [0, 0, 0, 0]; //[bottom left, top left, br, tr]\nlet long_button_states = context.get(\"long_button_states\") || [0, 0, 0, 0]; //[bottom left, top left, br, tr]\n\nlet msg07 = {};\nlet msg08 = {};\nlet msg09 = {};\nlet msg10 = {};\nlet msg11 = {};\nlet msg12 = {};\nlet msg13 = {};\n\nmsg07.topic = \"b1_state\";\nmsg08.topic = \"b1_short\";\nmsg09.topic = \"b1_long\";\nmsg10.topic = \"b2_state\";\nmsg11.topic = \"b2_short\";\nmsg12.topic = \"b2_long\";\n\n/*\nmsg01.payload = x; // Switch status 1=pressed, 0=released;\nmsg02.payload = x; // 1=short press recognised\nmsg03.payload = x; // 1=long press recognised, 0=long press released\n*/\n\nif (msg.topic == \"timer_long_press_elapsed\") //Timer for long press detection elapsed\n{\n wait_timer_return = 0;\n context.set(\"wait_timer_return\", 0);\n\n //detect, if we wait for Longpress detection --> send long pressed event\n\n /// ****************** Start of long_button_state press section **********************\n {\n if (button_states[2] == 1) {\n msg07 = null;\n msg08 = null;\n msg09.payload = 1;\n long_button_states[2] = 1;\n }\n else {\n long_button_states[2] = 0;\n msg07 = null;\n msg08 = null;\n msg09 = null;\n }\n\n if (button_states[3] == 1) {\n msg10 = null;\n msg11 = null;\n msg12.payload = 1;\n long_button_states[3] = 1;\n }\n else {\n long_button_states[3] = 0;\n msg10 = null;\n msg11 = null;\n msg12 = null;\n }\n\n context.set(\"long_button_states\", long_button_states);\n\n msg13 = null;\n }\n /// ****************** End of of long_button_state press section **********************\n}\nelse\n{\n if (msg.payload[0] != 0) //some button pressed\n {\n wait_timer_return = 1;\n context.set(\"wait_timer_return\", 1);\n\n msg13.topic = \"timer_long_press_elapsed\";\n msg13.id = msg._msgid;\n\n //Which bottom is pressed:\n let button1 = msg.payload[0] & 0xF0;\n button1 = button1 >> 4;\n\n let button2 = msg.payload[0] & 0x0F;\n\n button_states[0] = 0;\n button_states[1] = 0;\n button_states[2] = 0;\n button_states[3] = 0;\n \n switch (button1)\n {\n case 5:\n button_states[2] = 1;\n msg07.payload = 1;\n msg08 = null;\n msg09 = null;\n break;\n case 7:\n button_states[3] = 1;\n msg10.payload = 1;\n msg11 = null;\n msg12 = null;\n break;\n }\n switch (button2) {\n case 5:\n button_states[2] = 1;\n msg07.payload = 1;\n msg08 = null;\n msg09 = null;\n break;\n case 7:\n button_states[3] = 1;\n msg10.payload = 1;\n msg11 = null;\n msg12 = null;\n break;\n }\n\n context.set(\"button_states\", button_states);\n \n if (button_states[2] == 0)\n {\n msg07 = null;\n msg08 = null;\n msg09 = null;\n }\n if (button_states[3] == 0)\n {\n msg10 = null;\n msg11 = null;\n msg12 = null;\n } \n }\n else //button released\n {\n msg13 = null;\n\n /// ****************** Start of button state section **********************\n {\n\n if (button_states[2] == 1) {\n msg07.payload = 0;\n }\n else {\n msg07 = null;\n }\n\n if (button_states[3] == 1) {\n msg10.payload = 0;\n }\n else {\n msg10 = null;\n }\n\n context.set(\"button_states\", [0, 0, 0, 0]);\n }\n /// ****************** End of button state section **********************\n\n /// ****************** Start of long_button_state release section **********************\n {\n\n if (long_button_states[2] == 1) {\n msg08 = null;\n msg09.payload = 0;\n msg11 = null;\n }\n else {\n msg09 = null;\n }\n\n if (long_button_states[3] == 1) {\n msg11 = null;\n msg12.payload = 0;\n msg08 = null;\n }\n else {\n msg12 = null;\n }\n\n context.set(\"long_button_states\", [0, 0, 0, 0]);\n }\n /// ****************** End of of long_button_state release section **********************\n\n /// ****************** Start of button short section **********************\n {\n if (wait_timer_return == 1)\n {\n\n if (button_states[2] == 1) {\n msg08.payload = 1;\n msg09 = null;\n }\n else\n {\n msg08 = null;\n }\n\n if (button_states[3] == 1) {\n msg11.payload = 1;\n msg12 = null;\n }\n else\n {\n msg11 = null;\n }\n }\n }\n /// ****************** Emd of button short section **********************\n\n wait_timer_return = 0;\n context.set(\"wait_timer_return\", 0);\n }\n}\n\n\nreturn [msg07, msg08, msg09, msg10, msg11, msg12, msg13];",
"outputs": 7,
"timeout": 0,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 450,
"y": 100,
"wires": [
[],
[],
[],
[],
[],
[],
[
"54830c406fa7e126"
]
],
"outputLabels": [
"Button 1 (bottom) status (pressed 1 / released 0)",
"Button 1 (bottom) short press (1)",
"Button 1 (bottom) long press (start 1 / end 0)",
"Button 2 (top) status (pressed 1 / released 0)",
"Button 2 (top) short press (1)",
"Button 2 (top) long press (start 1 / end 0)",
"Start timer for long button press recognition"
],
"icon": "font-awesome/fa-toggle-on"
},
{
"id": "54830c406fa7e126",
"type": "delay",
"z": "cf80121d93fd6aa6",
"name": "Longpress time",
"pauseType": "delay",
"timeout": "300",
"timeoutUnits": "milliseconds",
"rate": "1",
"nbRateUnits": "1",
"rateUnits": "second",
"randomFirst": "1",
"randomLast": "5",
"randomUnits": "seconds",
"drop": false,
"allowrate": false,
"outputs": 1,
"x": 440,
"y": 200,
"wires": [
[
"93ac0df52d8e9698"
]
]
},
{
"id": "9c9e7e65436a5109",
"type": "mqtt-broker",
"name": "local MQTT broker",
"broker": "localhost",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"autoUnsubscribe": true,
"birthTopic": "",
"birthQos": "0",
"birthRetain": "false",
"birthPayload": "",
"birthMsg": {},
"closeTopic": "",
"closeQos": "0",
"closeRetain": "false",
"closePayload": "",
"closeMsg": {},
"willTopic": "",
"willQos": "0",
"willRetain": "false",
"willPayload": "",
"willMsg": {},
"userProps": "",
"sessionExpiry": ""
}
]