You’ve been busy!
The “Bedroom Strip” with a bit of Tina’s ‘Private Dancer’ playing in the background certainly sounds interesting!
Pete.
You’ve been busy!
The “Bedroom Strip” with a bit of Tina’s ‘Private Dancer’ playing in the background certainly sounds interesting!
Pete.
Device ID & RSSI are shown here
Components for:
I am using a custom component that works fine.
I am receiving warnings from HA but every thing is OK
You are using a custom component for sonoff.switch which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you do experience issues with Home Assistant.
3:21 PM loader.py (WARNING)
You are using a custom component for sonoff.sensor which has not been tested by Home Assistant. This component might cause stability problems, be sure to disable it if you do experience issues with Home Assistant.
3:21 PM loader.py (WARNING)
Model | Supported | 1.6 | 1.8.1 | 2.6 | 2.6.1 | 2.7.1 | 3.0.0 | Remarks |
---|---|---|---|---|---|---|---|---|
Sonoff Basic | yes | yes | yes | yes | yes | |||
Sonoff Dual | yes | |||||||
Sonoff RF | yes | yes | yes | |||||
Sonoff G1 | ? | |||||||
Sonoff 4CH Pro | yes | yes | yes | |||||
Sonoff 4CH Pro R2 | yes | yes | ||||||
Sonoff S20 | yes | yes | yes | |||||
Sonoff S31 | yes | |||||||
Sonoff S26 | yes | yes | yes | version: Euro | ||||
Sonoff T1 1C | yes | yes | ||||||
Sonoff T1 EU 2C | yes | yes | ||||||
Sonoff T1 UK 3C | yes | yes | yes | |||||
Sonoff T1 US 3C | yes | |||||||
Sonoff Pow | yes | + power sensor | ||||||
Sonoff Pow R2 | yes | + power/current/voltage sensors | ||||||
Sonoff TH10/TH16 | yes | + temp/humidity sensors | ||||||
Sonoff iFan02 | yes | it creates 4 switches, 1 for the light and 3 for the various fan speeds | ||||||
Sonoff HT-TH31 | ? | |||||||
Sonoff Slampher RF | yes | yes | yes | |||||
3 Gang Generic Wall Switch | yes | yes | Manfufacturer: pro-sw, Model: PS-15-ES (according to ewelink app) | |||||
1 Gang Generic Wall Switch | yes | yes | yes | manfufacturer: KingART, model: KING-N1 (according to ewelink app), Chip: PSF-B85 (ESP8285) | ||||
WHDTS WiFi Momentary Inching Relay | yes | displayed as a switch button | ||||||
MHCOZY WiFi Wireless 5V/12V | yes | |||||||
Geekcreit 2 Channel AC 85V-250V | yes | yes | ||||||
Smart Wi-Fi Outlet | yes |
yes
= confirmed version, [empty] = unknown for sure
As we see all components are using .py extension to work with HA
HASS-sonoff-ewelink/sensor/ sonoff.py
HASS-sonoff-ewelink/switch/ sonoff.py
Here I am asking if there is anyone on this forum having a good knowledge of python programming language to help us translating this to BLYNK without the need to change the SONOFF firmware to TASMOTA to be able to use MQTT publish and subscribe message protocol.
Continuing the discussion from Hacking the new ITEAD Studio - Sonoff S31
Today I think I knew how Peter Buga can control Sonoff / eWeLink smart devices.
Download and install Python 2.x or 3.x from https://www.python.org/downloads
Go to sonoff-debug.py
To run this just, cd
to the location of the script and:
python sonoff-debug.py -u 'email or phone-number username' -p 'password'
> devices.json
you will get a file named “devices.json”
this is one of my Sonoff POW R2 but the file contain all Sonoffs in my Home.
if you take a close look to the file you will find all the variables power, voltage, current, rssi, device id, and more…
[
{
"__v": 0,
"_id": "[hidden]",
"apikey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"brandLogoUrl": "",
"brandName": "Sonoff",
"createdAt": "xxxx-xx-xxxxx:xx:xx.xxx",
"deviceStatus": "",
"deviceUrl": "",
"deviceid": "[hidden]",
"devicekey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"extra": {
"_id": "[hidden]",
"extra": {
"apmac": "xx:xx:xx:xx:xx:xx",
"brandId": "58e5f344baeb368720e25469",
"description": "WO1881982",
"mac": "xx:xx:xx:xx:xx:xx",
"manufacturer": "\u6df1\u5733\u677e\u8bfa\u6280\u672f\u6709\u9650\u516c\u53f8",
"model": "PSC-B67-GL",
"modelInfo": "5a2e1ae50cf772f92c342ef6",
"ui": "\u529f\u7387\u68c0\u6d4b\u63d2\u5ea7\u8fc7\u8f7d\u544a\u8b66",
"uiid": 32
}
},
"group": "",
"groups": [],
"ip": "[hidden]",
"location": "",
"name": "[hidden]",,
"offlineTime": "xxxx-xx-xxxxx:xx:xx.xxx",
"online": true,
"onlineTime": "xxxx-xx-xxxxx:xx:xx.xxx",
"params": {
"alarmCValue": [
-1,
10
],
"alarmPValue": [
-1,
-1
],
"alarmType": "pcv",
"alarmVValue": [
-1,
240
],
"bindInfos": {
"alexa": [
"xxxxxx-xxxx-xxxxx-xxxxx-xxxxxxxxxxxxx_26ca1996a20e8bd63617axxxxxxxxxxxxxxxxxxxx"
],
"gaction": [
"xxxxxxxxxx-xxxxx-xxxxxx-xxxxxxxxxxx_ewelink-google-home-v1"
]
},
"current": "0.28",
"endTime": "xxxx-xx-xxxxx:xx:xx.xxx",
"fwVersion": "2.8.0",
"hundredDaysKwh": "get",
"init": 1,
"oneKwh": "stop",
"partnerApikey": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"power": "59.81",
"rssi": -71,
"sledOnline": "on",
"staMac": "xx:xx:xx:xx:xx:xx",
"startTime": "xxxx-xx-xxxxx:xx:xx.xxx",
"startup": "stay",
"switch": "on",
"timeZone": 2,
"voltage": "234.57"
},
"productModel": "Pow_R2",
"settings": {
"alarmNotify": 1,
"opsHistory": 1,
"opsNotify": 0
},
"sharedTo": [
{
"nickname": "Pico",
"note": "",
"permit": 15,
"phoneNumber": "[hidden]",,
"shareTime": 1551282301502
}
],
"showBrand": true,
"type": "10",
"uiid": 32
},
to remove all hidden information in this file go to sonoff-debug.py and comment
data = re.sub(r'"phoneNumber": ".*"', '"phoneNumber": "[hidden]",', data)
data = re.sub(r'"name": ".*"', '"name": "[hidden]",', data)
data = re.sub(r'"ip": ".*",', '"ip": "[hidden]",', data)
data = re.sub(r'"deviceid": ".*",', '"deviceid": "[hidden]",', data)
data = re.sub(r'"_id": ".*",', '"_id": "[hidden]",', data)
data = re.sub(r'"\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2}"', '"xx:xx:xx:xx:xx:xx"', data)
data = re.sub(r'"\w{8}-\w{4}-\w{4}-\w{4}-\w{12}"', '"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"', data)
data = re.sub(r'"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z"', '"xxxx-xx-xxxxx:xx:xx.xxx"', data)
before running the script .
at end I think https://community.home-assistant.io/u/peterbuga has done a great job
and here is what he wrote:
the data that you see/get, it’s exactly what I get from eWeLink API and nothing more.
I recently found out that sensor data is propagated over websocket messages too, not just basic requests (as it now), when I do find the time I’ll update the component to take advantage of this and hopefully an overall better output
Understanding MQTT: How Smart Home Devices Communicate
Add a door sensor to any door with a Sonoff basic.
Fix Random Switching in Tasmota by Adjusting Retain Settings
Effectively, he recommends :
Make sure you have set the retain to false in Home Assistant Configuration.
Restart the Home Assistant server .
Send these commands to the Sonoff in the console menu.
switchretain off
buttonretain on
buttonretain off
poweronstate 3
powerretain on
IF you don’t have a Raspberry PI to install Mosquitto broker and need an MQTT that works with BLYNK here is the cheapest and easiest solution.
the CODE works on any ESP8266 NodeMCU, Wemo D1 ,Sonoff Basic (Tested)
// uMQTTBroker for Sonoff
//
// The program simply starts a broker and waits for any client to connect.
// maximal 10 Client possible
//
///////////////////////////////////////////////////////////////////////////////
#include "ESP8266WiFi.h"
#include "uMQTTBroker.h"
#include "espconn.h"
// Your WiFi config here //////////////////////////////////////////////////////
char host[] = "ESP-MQTT"; // Hostname
char ssid[] = "ssid"; // your network SSID (name)
char pass[] = "password"; // your network password
bool STATIC = false; // Static IP for STA Mode? [false/true]
IPAddress ip(192,168,1,200); // Static IP
IPAddress gw(192,168,1,1); // Gateway
IPAddress su(255,255,255,0); // Subnet
bool WiFiAP = false; // Do yo want the ESP as AP? [false/true]
bool EXAMPL = true; // Example Progamm on/off? [false/true]
// Example need rule in Test_1
// rule1 on power1#state=1 do publish stat/TEST_1/POWER TRUE endon on power1#state=0 do publish stat/TEST_1/POWER FALSE endon
// Declare Variable ///////////////////////////////////////////////////////////
String RECEIVE; // Received Topic for logical operations
String RECEVAL; // Received Topic for logical operations
int GPIO0 = 0; // GPIO0 -> Sonoff Basic - Button
int GPIO12 = 12; // GPIO12 -> Sonoff Basic - Relais
int GPIO13 = 13; // GPIO13 -> Sonoff Basic - green LED
int GPIO14 = 14; // GPIO14 -> Sonoff Basic - Optional Sensor
int BSTAT1; // State Button GPIO0
int RSTAT1; // State Relais GPIO12
int TRIGG1 = LOW;
class myMQTTBroker: public uMQTTBroker
{
public:
virtual bool onConnect(IPAddress addr, uint16_t client_count) {
Serial.println(addr.toString()+" connected");
return true;
}
virtual bool onAuth(String MQTTUSER, String MQTTPASS) {
Serial.println("Username/Password: "+MQTTUSER+"/"+MQTTPASS);
return true;
}
virtual void onData(String topic, const char *data, uint32_t length) {
char data_chr[length+1];
os_memcpy(data_chr, data, length);
data_chr[length] = '\0';
String data_str = (String)data_chr;
data_str.toUpperCase();
RECEVAL = topic+" "+data_str;
Serial.println("received: "+RECEVAL);
}
};
void MQTT_Server_cleanupClientCons();
myMQTTBroker myBroker;
// WiFi init stuff ////////////////////////////////////////////////////////////
void startWiFiClient()
{
if (STATIC) {
WiFi.config(ip, gw, gw, su);
}
WiFi.softAPdisconnect(true);
WiFi.hostname(host);
Serial.println("Connecting to "+(String)ssid);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: " + WiFi.localIP().toString());
}
void startWiFiAP()
{
WiFi.softAP(ssid, pass);
Serial.println("AP started");
Serial.println("IP address: " + WiFi.softAPIP().toString());
}
void setup()
{
// Configure GPIO //////////////////////////////////////////////////////////
pinMode(GPIO0, INPUT_PULLUP);
pinMode(GPIO12, OUTPUT);
pinMode(GPIO13, OUTPUT);
pinMode(GPIO14, OUTPUT);
// Serial Interface
Serial.begin(115200);
Serial.println();
Serial.println();
// Start WiFi
espconn_tcp_set_max_con(10);
if (WiFiAP) {
startWiFiAP();
} else {
startWiFiClient();
}
// Start the broker
Serial.println("Starting MQTT broker");
myBroker.init();
// Subscribe to anything ////////////////////////////////////////////////////
myBroker.subscribe("#");
}
void loop()
{
RECEIVE = RECEVAL;
// Example Programm /////////////////////////////////////////////////////////
if (EXAMPL) {
if (RECEIVE.equals("stat/TEST_1/POWER FALSE")) {
myBroker.publish("cmnd/TEST_2/POWER", "ON");
}
if (RECEIVE.equals("stat/TEST_1/POWER TRUE")) {
myBroker.publish("cmnd/TEST_2/POWER", "OFF");
}
}
if (RECEIVE.equals("cmnd/"+(String)host+"/STATUS 1")) {
myBroker.publish("cmnd/TEST_1/POWER", "(null)");
myBroker.publish("cmnd/TEST_2/POWER", "(null)");
if (RSTAT1 == LOW) {
myBroker.publish("stat/"+(String)host+"/POWER", "OFF");
} else {
myBroker.publish("stat/"+(String)host+"/POWER", "ON");
}
}
/////////////////////////////////////////////////////////////////////////////
// Basic Function Button/MQTT ///////////////////////////////////////////////
BSTAT1 = digitalRead(GPIO0);
RSTAT1 = digitalRead(GPIO12);
// Button event /////////////////////////////////////////////////////////////
if (BSTAT1 == LOW and RSTAT1 == LOW and TRIGG1 == LOW) {
digitalWrite(GPIO12, HIGH);
TRIGG1 = HIGH;
Serial.println("GPIO0 POWER ON");
myBroker.publish("stat/"+(String)host+"/POWER", "ON");
}
if (BSTAT1 == LOW and RSTAT1 == HIGH and TRIGG1 == LOW) {
digitalWrite(GPIO12, LOW);
TRIGG1 = HIGH;
Serial.println("GPIO0 POWER OFF");
myBroker.publish("stat/"+(String)host+"/POWER", "OFF");
}
if (BSTAT1 == HIGH) { TRIGG1 = LOW; }
// MQTT event ///////////////////////////////////////////////////////////////
if (RECEIVE.equals("cmnd/"+(String)host+"/POWER ON")) {
digitalWrite(GPIO12, HIGH);
Serial.println("stat/"+(String)host+"/POWER ON");
myBroker.publish("stat/"+(String)host+"/POWER", "ON");
delay(50);
}
if (RECEIVE.equals("cmnd/"+(String)host+"/POWER OFF")) {
digitalWrite(GPIO12, LOW);
Serial.println("stat/"+(String)host+"/POWER OFF");
myBroker.publish("stat/"+(String)host+"/POWER", "OFF");
delay(50);
}
if (RECEIVE.equals("cmnd/"+(String)host+"/POWER ")) {
if (RSTAT1 == LOW) {
myBroker.publish("stat/"+(String)host+"/POWER", "OFF");
} else {
myBroker.publish("stat/"+(String)host+"/POWER", "ON");
}
}
// LED STATUS ///////////////////////////////////////////////////////////////
if (RSTAT1 == LOW) {
digitalWrite(GPIO13, HIGH);
} else {
digitalWrite(GPIO13, LOW);
}
}
you can test it with
https://play.google.com/store/apps/details?id=com.thn.iotmqttdashboard
I even test “uMQTT broker” with HA and it works OK
==============================================================================
23:53:24 MQT: stairs/Distance = {"Distance":40.842}
23:53:24 MQT: stairs/tele/STATE = {"Time":"2019-03-19T23:53:24","Uptime":"0T01:11:57","Vcc":2.973,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":43,"POWER1":"ON","POWER2":"OFF","POWER3":"ON","Wifi":{"AP":1,"SSId":"BLYNK","BSSId":"48:F8:B3:84:AB:22","Channel":10,"RSSI":70,"LinkCount":1,"Downtime":"0T00:00:04"}}
23:53:24 MQT: stairs/tele/SENSOR = {"Time":"2019-03-19T23:53:24","Switch1":"OFF","DS18B20-1":{"Id":"000006F242B1","Temperature":21.5},"DS18B20-2":{"Id":"000006F2B80A","Temperature":21.6},"DS18B20-3":{"Id":"00000789E508","Temperature":21.5},"DS18B20-4":{"Id":"8000001F18D8","Temperature":21.5},"AM2301":{"Temperature":21.3,"Humidity":69.5},"SR04":{"Distance":40.404},"TempUnit":"C"}
23:53:24 MQT: stairs/tele/STATE = {"Time":"2019-03-19T23:53:24","Uptime":"0T01:11:57","Vcc":2.980,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":77,"POWER1":"ON","POWER2":"OFF","POWER3":"ON","Wifi":{"AP":1,"SSId":"BLYNK","BSSId":"48:F8:B3:84:AB:22","Channel":10,"RSSI":68,"LinkCount":1,"Downtime":"0T00:00:04"}}
23:53:24 MQT: stairs/stat/RESULT = {"POWER2":"OFF"}
23:53:24 MQT: stairs/stat/POWER2 = OFF
23:53:26 RUL: SR04#DISTANCE>%VAR2% performs "backlog publish stairs/Distance {"Distance":40.456};power2 off"
00:03:06 MQT: stairs/stat/RESULT = {"POWER1":"ON"}
00:03:06 MQT: stairs/stat/POWER1 = ON
00:03:06 MQT: stairs/stat/RESULT = {"T1":30,"T2":0,"T3":0,"T4":0,"T5":0,"T6":0,"T7":0,"T8":0}
00:03:06 RUL: SR04#DISTANCE<%VAR2% performs "backlog publish stairs/Distance {"Distance":17.298};power2 on"
00:03:06 MQT: stairs/Distance = {"Distance":17.298}
controlling NodeMCU flashed by a recent Tasmota bin.file or (sketch) as explained in post #2
BLYNK is running on another NodeMCU or simply an ESP8266-01 because in this example we don’t need hardware pins.
before we continue the most important is to send our Rules to Tasmota and be sure it is acting as we plan.
Backlog PowerRetain 1; module 18; gpio00 17; gpio01 04; gpio2 29; gpio3 02; gpio4 06; gpio5 05; gpio12 73; gpio13 74; gpio14 82; gpio15 00; gpio16 30; setoption8 0; teleperiod 30
RULES
mem1 30
switchmode1 1
Rule1 on switch1#state do publish stairs/PIR_stairs/state %value% endon
rule1 1
Rule2 on Switch1#state=1 do backlog event AutoMotion=%mem2%; publish stairs/mem2/state %mem2% endon on event#AutoMotion==1 do backlog power1 on; ruletimer1 %mem1% endon on rules#timer=1 do power1 off endon on event#AutoMotion==0 do RuleTimer1 0 endon
Rule3 on SR04#Distance<%var2% do backlog publish stairs/Distance {"Distance":%value%};power1 on; ruletimer2 %mem1% endon on rules#timer=2 do power1 off endon on SR04#Distance do backlog publish stairs/Distance {"Distance":%value%} endon
Be sure to write each Rule on one line.
After sending a rule you must turn it on by
Rule(x) 1
(x) is 1 or 2 or 3
To turn OFF a Rule.
Rule1 0
for Tasmota to be discovered by Home Assistant.
setoption19 1
NODE_MQTT_PIR_TEMP.ino
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <BlynkSimpleEsp8266.h>
#define BLYNK_PRINT Serial // Comment this out to disable prints and save space
#include "Settings.h"
#include "mqtt_publish.h"
#include "timer.h"
#include "mqtt_subscribe.h"
#include "wifi_credentials.h"
/*-------------------------------- Setup -------------------------------------*/
void setup() {
WiFi.mode(WIFI_STA);
Serial.begin(115200); // See the connection status in Serial Monitor
Serial.println(F("\n Setup STARTING"));
WiFi.begin(WIFI_SSID, WIFI_PASS);
if(WiFi.status() == 6) Serial.println("\tWiFi not connected yet.");
//----------------------------------Blynk------------------------------------
#ifdef LOCAL_SERVER
Blynk.config(AUTH, LOCAL_SERVER ,8080);
#else
Blynk.config(AUTH, Geo_DNS_SERVER);
#endif
while (Blynk.connect() == false) { // Wait until connected
if ((millis() - last_UP_change) > 30000) { // 30s before reset
Serial.println(F("resetting"));
ESP.restart();
}
}
client.setServer(MQTT_SERVER, 1883);
client.setCallback(callback);
//-----------------------------------OTA--------------------------------------
ArduinoOTA.setHostname(OTA_HOSTNAME);
// ArduinoOTA.setPassword(OTA_PASSWORD); //If you need a Password uncomment this line
ArduinoOTA.begin();
Serial.println(F(" Entering loop"));
timer.setInterval(4000L, Heartbeat); // Heartbeat 4000L
CountdownTimer = timer.setInterval(1000, CountdownTimerFunction);
timer.disable(CountdownTimer); // disable it on boot
Blynk.syncVirtual(vPIN_ON_OFF_1);
Blynk.syncVirtual(vPIN_ON_OFF_2);
Blynk.syncVirtual(vPIN_AUTO_MOTION);
Blynk.syncVirtual(vPIN_NUMERIC_TIMER);
Blynk.virtualWrite(vPIN_COUNTDOWN, " 0:00:00" );
Blynk.setProperty(vPIN_ON_OFF_1, "label", String("T1 = ") + "0:00:00" + String(" S") );
Blynk.setProperty(vPIN_PIR_LED, "label", String ("PIR <---- ") + memory1 + String(" S") );
Blynk.setProperty(vPIN_HEARTBEAT, "label", String("\xF0\x9F\x92\x93") + " HEARTBEAT");
}
/*----------------------------------Loop--------------------------------------*/
void loop() {
Blynk.run();
if(!Blynk.connected()) {
Serial.println(F("Resetting in loop"));
ESP.restart();
}
timer.run();
if (!client.connected()) {
reconnect();
}
client.loop();
ArduinoOTA.handle();
}
/*=============================================================================*/
Settings.h
/*****************************************************************************
*
* Settings.h
*
*****************************************************************************/
/*---------------------------Blynk Auth Code----------------------------------*/
#define AUTH "*******************************************" // NodeMCU
/*-------------------------Over The Air Hostname------------------------------*/
#define OTA_HOSTNAME "N-MQTT_Bridge" // put here your host name
#define OTA_PASSWORD "blynk" // your password for OTA if needed
/*----------------------------Hardware Pins-----------------------------------*/
/*-NodeMCU#*/
/*-------------------------------Virtual Pins---------------------------------*/
#define vPIN_HEARTBEAT V0
#define vPIN_DS18B20_1_TEMP V1
#define vPIN_DS18B20_2_TEMP V2
#define vPIN_DS18B20_3_TEMP V3
#define vPIN_DS18B20_4_TEMP V4
#define vPIN_AM2301_TEMP V5
#define vPIN_AM2301_HUM V6
#define vPIN_SR04_DIST V7
#define vPIN_PIR_LED V8
#define vPIN_TEMP_UNIT V9
#define vPIN_HUM V10
#define vPIN_ALL_TEMP V11
#define vPIN_ON_OFF_1 V21 // ON/OFF POWER 1 Activated by Motion (Tasmota Rule1 & Rule2)
#define vPIN_AUTO_MOTION V22 // when motion is detected Relay1 turns on for timer sec & repeats
#define vPIN_NUMERIC_TIMER V23 // up to 32767 ~9hrs
#define vPIN_COUNTDOWN V24 // triggered by motion countdown for timer sec and restart with each PIR trigger
#define vPIN_AUTO_SR04 V25 // Activate/Desactivate Rule3
#define vPIN_ON_OFF_2 V31 // ON/OFF POWER 2 Activated by Sun
/*-----------------------------variables-------------------------------------*/
bool memory2 ;
int memory1 ;
int counter = 0;
int CountdownTimer;
int CountdownRemain;
long int last_UP_change = millis();
int rssi;
float Vcc;
float Distance;
mqtt_publish.h
/******************************************************************************
*
* mqtt_publish.h
*
*****************************************************************************/
WiFiClient espClient;
PubSubClient client(espClient);
BlynkTimer timer;
//----------------------------------------------℃/℉-----------------------------------------------------------
BLYNK_WRITE(vPIN_TEMP_UNIT) { // Change Temp. Unit from Celsius ℃ to Fahrenheit
if (param.asInt()) {
client.publish("stairs/cmnd/setoption8","1"); // Fahrenheit ℉
Blynk.setProperty(vPIN_TEMP_UNIT, "label",String("\xf0\x9f\x8c\xa1") + "Fahrenheit ℉");
} else {
client.publish("stairs/cmnd/setoption8","0"); // Celcius ℃
Blynk.setProperty(vPIN_TEMP_UNIT, "label",String("\xf0\x9f\x8c\xa1") + " Celsius ℃");
}
}
//---------------------------------------------POWER1----(Motion)-------------------------------------------
BLYNK_WRITE(vPIN_ON_OFF_1) { // ON/OFF switch
if (param.asInt()) {
client.publish("stairs/cmnd/POWER1","1");
} else {
client.publish("stairs/cmnd/POWER1","0");
}
}
BLYNK_WRITE(vPIN_AUTO_MOTION) { // AUTO/Manual
if (param.asInt()) {
client.publish("stairs/cmnd/mem2","1");
Blynk.setProperty(vPIN_AUTO_MOTION, "label",String("\xF0\x9F\x92\xAB") + " AUTO PIR");
memory2 = 1;
} else {
client.publish("stairs/cmnd/mem2","0");
Blynk.setProperty (vPIN_AUTO_MOTION, "label",String("\xE2\x9C\x8B") + " MANUAL PIR");
memory2 = 0;
CountdownRemain = 1;
}
}
BLYNK_WRITE(vPIN_NUMERIC_TIMER) { // TIMER 0-300 Sec up to 32767sec [9hr:06min:07sec]
int VALUE = param.asInt();
char value[4];
dtostrf(VALUE, 3, 0, value);
client.publish("stairs/cmnd/Mem1", value);
Blynk.setProperty(vPIN_PIR_LED, "label", String("PIR <---- ") + value + String(" S") );
if (memory2 == 1) {
client.publish("stairs/cmnd/POWER1", "ON");
} else {
CountdownRemain = 1;
}
}
//-----------------------------------------------SR04---------------------------------------------------
BLYNK_WRITE(vPIN_AUTO_SR04) { // AUTO/Manual
if (param.asInt()) {
client.publish("stairs/cmnd/Rule3","1");
Blynk.setProperty(vPIN_AUTO_SR04, "label",String("\xF0\x9F\x92\xAB") + " AUTO SR04");
} else {
client.publish("stairs/cmnd/Rule3","0");
Blynk.setProperty (vPIN_AUTO_SR04, "label",String("\xE2\x9C\x8B") + " MANUAL SR04");
}
}
//---------------------------------------------POWER2----(Sun)-------------------------------------------
BLYNK_WRITE(vPIN_ON_OFF_2) { // ON/OFF switch
if (param.asInt()) {
client.publish("stairs/cmnd/POWER2","1");
} else {
client.publish("stairs/cmnd/POWER2","0");
}
}
/*--------------------------------Heartbeat--------------------------------*/
void Heartbeat() {
Blynk.virtualWrite(vPIN_HEARTBEAT," \xF0\x9F\x92\x96"); //
timer.setTimeout(2000L,[](){Blynk.virtualWrite(vPIN_HEARTBEAT," \xF0\x9F\x92\x97");});
}
/*--------------------------------------------------------------------------*/
mqtt_subscribe.h
/*******************************************************************************
*
* mqtt_subscribe.h
*
******************************************************************************/
#define MQTT_SERVER IPAddress(192,168,xxx,xxx) // Your MQTT Broker IP address
#define MQTT_USERNAME "xxxx" // put here your MQTT username
#define MQTT_PASSWORD "xxxx" // put here your MQTT password
#define InTOPIC_0 "stairs/tele/STATE"
#define InTOPIC_1 "stairs/tele/SENSOR"
#define InTOPIC_2 "stairs/PIR_stairs/state"
#define InTOPIC_3 "stairs/stat/POWER1"
#define InTOPIC_4 "stairs/stat/POWER2"
#define InTOPIC_5 "stairs/Distance"
#define InTOPIC_6 "stairs/stat/RESULT"
void reconnect() { // Loop until we're reconnected
while (!client.connected()) {
Serial.print(" Attempting MQTT connection..."); // Attempt to connect
if (client.connect("DVES",MQTT_USERNAME,MQTT_PASSWORD)) {
Serial.println("connected");
counter = 0; // ... and resubscribe
client.subscribe(InTOPIC_0);
client.subscribe(InTOPIC_1);
client.subscribe(InTOPIC_2);
client.subscribe(InTOPIC_3);
client.subscribe(InTOPIC_4);
client.subscribe(InTOPIC_5);
client.subscribe(InTOPIC_6);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 0.3 second");
++counter;
if (counter > 180) ESP.reset(); // Wait .3 seconds before retrying
delay(300);
}
}
}
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();
Serial.println();
//-------------------------------------------STATE------------------------------------------------
// MQT: stairs/tele/STATE =
// {"Time":"2019-03-18T17:56:18","Uptime":"0T18:23:11","Vcc":3.002,"SleepMode":"Dynamic",
// "Sleep":50,"LoadAvg":19,"POWER1":"ON","POWER2":"OFF","Wifi":{"AP":1,"SSId":"BLYNK",
// "BSSId":"48:F8:B3:84:AB:22","Channel":10,"RSSI":84,"LinkCount":6,"Downtime":"0T00:00:21"}}
if (String(topic) == InTOPIC_0) { // stairs/tele/STATE
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
Vcc = root["Vcc"]; // 3.002
rssi = root["Wifi"]["RSSI"]; // 84
// const char* Time = root["Time"]; // 2019-03-18T17:56:18
// const char* Uptime = root["Uptime"]; // 0T18:23:11
// const char* SleepMode = root["SleepMode"];// Dynamic
// int Sleep = root["Sleep"]; // 50
// int LoadAvg = root["LoadAvg"]; // 19
// const char* POWER1 = root["POWER1"]; // ON
// const char* POWER2 = root["POWER2"]; // OFF
// int AP = root["Wifi"]["AP"]; // 1
// const char* SSId = root["Wifi"]["SSId"]; // BLYNK
// const char* BSSId = root["Wifi"]["BSSId"];// 48:F8:B3:84:AB:22
// int Chl = root["Wifi"]["Channel"];// 10
// int LC= root["Wifi"]["LinkCount"];// 6
// const char* DT = root["Wifi"]["Downtime"];// 0T00:00:21
//-------------------------------------------SENSOR-----------------------------------------------
//MQT: stairs/tele/SENSOR =
//{"Time":"2019-03-19T13:19:16","Switch1":"OFF","DS18B20-1":{"Id":"000006F242B1","Temperature":21.9},
//"DS18B20-2":{"Id":"000006F2B80A","Temperature":22.0},"DS18B20-3":{"Id":"00000789E508","Temperature":21.9},
//"DS18B20-4":{"Id":"8000001F18D8","Temperature":22.6},"AM2301":{"Temperature":22.0,"Humidity":68.7},
//"ADS1115":[{"A0":-1,"A1":26033,"A2":4851,"A3":4809}],"SR04":{"Distance":40.509},"TempUnit":"C"}
}else if (String(topic) == InTOPIC_1) { // stairs/tele/SENSOR
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
const char* Time = root["Time"]; // 2019-03-19T13:19:16
float DS1_T = root["DS18B20-1"]["Temperature"]; // 21.9
float DS2_T = root["DS18B20-2"]["Temperature"]; // 22.0
float DS3_T = root["DS18B20-3"]["Temperature"]; // 21.9
float DS4_T = root["DS18B20-4"]["Temperature"]; // 22.6
float Temp = root["AM2301"]["Temperature"]; // 22.0
float Hum = root["AM2301"]["Humidity"]; // 68.7
float Dist = root["SR04"]["Distance"]; // 40.509
// const char* Switch1 = root["Switch1"]; // OFF
// const char* DS1_ID = root["DS18B20-1"]["Id"]; // 000006F242B1
// const char* DS2_ID = root["DS18B20-2"]["Id"]; // 000006F2B80A
// const char* DS3_ID = root["DS18B20-3"]["Id"]; // 00000789E508
// const char* DS4_ID = root["DS18B20-4"]["Id"]; // 8000001F18D8
// float ADS_A0 = root["ADS1115"]["A0"]; // -1
// float ADS_A1 = root["ADS1115"]["A1"]; // 26033
// float ADS_A2 = root["ADS1115"]["A2"]; // 4851
// float ADS_A3 = root["ADS1115"]["A3"]; // 4809
// const char* TU = root["TempUnit"];// "C"
// Blynk.virtualWrite(vPIN_DS18B20_1_TEMP,DS1_T);
// Blynk.virtualWrite(vPIN_DS18B20_2_TEMP,DS2_T);
// Blynk.virtualWrite(vPIN_DS18B20_3_TEMP,DS3_T);
// Blynk.virtualWrite(vPIN_DS18B20_4_TEMP,DS4_T);
// Blynk.virtualWrite(vPIN_AM2301_TEMP,Temp);
// Blynk.virtualWrite(vPIN_AM2301_HUM,Hum);
// Blynk.virtualWrite(vPIN_SR04_DIST,Dist);
Blynk.virtualWrite(vPIN_ALL_TEMP, (String (DS1_T,1)+" "+String (DS2_T,1)+" "+String (DS3_T,1)+" "+String (DS4_T,1)+" "+String (Temp,1)));
Blynk.setProperty (vPIN_ALL_TEMP, "label",String("\xf0\x9f\x8c\xa1") + "DS18B20-1 DS18B20-2 DS18B20-3 DSPROBE-4 "+String("\xf0\x9f\x8c\xa1")+"AM2302");
Blynk.virtualWrite(vPIN_HUM,String (Hum,1)+"%"+" "+String("\xF0\x9F\x93\xB6")+String (rssi)+"%"+" "+String(Vcc)+"V");
Blynk.setProperty (vPIN_HUM, "label",String("\xF0\x9F\x92\xA7")+"AM2302 Hum "+ String (Time)+" Vcc");
//--------------------------------------------PIR------------------------------------------------
}else if (String(topic) == InTOPIC_2) { // stairs/PIR_stairs/state = (1/0)
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
if ((char)payload[0] == '1') { // Switch1 on LED if 1 was received as first character
Blynk.virtualWrite(vPIN_PIR_LED,255);
Serial.println("PIR = ON");
Blynk.setProperty (vPIN_AUTO_MOTION, "label",String("\xF0\x9F\x9A\x85")+ "MOTION >>> detected");
}else{
Blynk.virtualWrite(vPIN_PIR_LED,0);
Serial.println("PIR = OFF");
if (memory2==1) {
Blynk.setProperty (vPIN_AUTO_MOTION, "label",String("\xF0\x9F\x92\xAB") + " AUTO PIR ");
} else {
Blynk.setProperty (vPIN_AUTO_MOTION, "label",String("\xE2\x9C\x8B") + " MANUAL PIR ");
}
}
//---------------------------------------------POWER1-----------------------------------------------
}else if (String(topic) == InTOPIC_3) { // stairs/stat/POWER1
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
if ((char)payload[1] == 'N') {
Blynk.virtualWrite(vPIN_ON_OFF_1,1);
Serial.println("POWER1 = ON");
}else{
Blynk.virtualWrite(vPIN_ON_OFF_1,0);
Serial.println("POWER1 = OFF");
}
//----------------------------------------------POWER2----------------------------------------------
}else if (String(topic) == InTOPIC_4) { // stairs/stat/POWER2
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
if ((char)payload[1] == 'N') {
Blynk.virtualWrite(vPIN_ON_OFF_2,1);
Serial.println("POWER2 = ON");
}else{
Blynk.virtualWrite(vPIN_ON_OFF_2,0);
Serial.println("POWER2 = OFF");
}
//--------------------------------------------------------------------------------------------
}else if (String(topic) == InTOPIC_5) { // stairs/Distance
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
Distance = root["Distance"];
Blynk.virtualWrite(vPIN_SR04_DIST,Distance);
Blynk.setProperty (vPIN_SR04_DIST, "label", "DISTANCE in Cm");
//--------------------------------------------------------------------------------------------
//09:59:13 MQT: stairs/stat/RESULT = {"T1":30,"T2":0,"T3":0,"T4":0,"T5":0,"T6":0,"T7":0,"T8":0}
//10:01:05 MQT: stairs/stat/RESULT = {"POWER1":"ON"}
//10:01:40 MQT: stairs/stat/RESULT = {"POWER1":"OFF"}
//10:04:11 MQT: stairs/stat/RESULT = {"Mem1":"20_"}
}else if (String(topic) == InTOPIC_6) { //stairs/stat/RESULT
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
int memory1 = root["Mem1"];
int T1 = root["T1"];
const char* POWER1 = root["POWER1"]; // "OFF"
if ( memory1 > 0) {
Blynk.setProperty(vPIN_PIR_LED, "label", String("PIR ") + memory1 + String(" S") );
CountdownRemain = memory1;
Serial.print("memory1 = "); Serial.print(memory1); Serial.println(" Sec");
Serial.println(CountdownRemain);
if (CountdownRemain) { // check if there is a time set or not
CountdownShowFormatted(CountdownRemain);
timer.enable(CountdownTimer);
}
}
if ( T1 > 0) {
Blynk.setProperty(vPIN_PIR_LED, "label", String("PIR ") + T1 + String(" S") );
CountdownRemain = T1;
if (CountdownRemain) { // check if there is a time set or not
CountdownShowFormatted(CountdownRemain);
timer.enable(CountdownTimer);
}
}
}
}
timer.h
/*******************************************************************************
*
* timer.h
*
*******************************************************************************/
void CountdownShowFormatted(int seconds) {
long hours = 0;
long mins = 0;
long secs = 0;
String secs_o = ":";
String mins_o = ":";
secs = seconds; // set the seconds remaining
mins = secs / 60; //convert seconds to minutes
hours = mins / 60; //convert minutes to hours
secs = secs - (mins * 60); //subtract the coverted seconds to minutes in order to display 59 secs max
mins = mins - (hours * 60); //subtract the coverted minutes to hours in order to display 59 minutes max
if (secs < 10) {
secs_o = ":0";
}
if (mins < 10) {
mins_o = ":0";
}
if (memory2 == 1){
Blynk.virtualWrite(vPIN_COUNTDOWN, String(" ")+ hours + mins_o + mins + secs_o + secs);
Blynk.setProperty(vPIN_ON_OFF_1, "label", String("\xE2\x8F\xB3") + String("T1 = ") + hours + mins_o + mins + secs_o + secs + String(" S"));
} else {
Blynk.virtualWrite(vPIN_COUNTDOWN, " 0:00:00");
Blynk.setProperty(vPIN_ON_OFF_1, "label", String("T1 = ") + "0:00:00" + String(" S") );
}
}
void CountdownTimerFunction() {
CountdownRemain--; // remove 1 every second
CountdownShowFormatted(CountdownRemain);
if (!CountdownRemain) { // check if CountdownRemain == 0/FALSE/LOW
timer.disable(CountdownTimer); // if 0 stop timer
if (memory2 == 1) {
Blynk.setProperty(vPIN_ON_OFF_1, "label", String("T1 = ") + "0:00:00" + String(" S") );
client.publish("stairs/cmnd/POWER1", "0");
}
}
}
wifi_credentials.h
/*******************************************************************************
*
* wifi_credentials.h
*
******************************************************************************/
/*******************************************************************************
Local Blynk Server Settings (uncomment to use local server and set address)
*******************************************************************************/
#define WIFI_SSID "xxxx" // ["xxxx" PW = "xxxx" ]
#define WIFI_PASS "xxxx" //Set pass to "" for open networks.
//#define LOCAL_SERVER IPAddress(192, 168,xxx, xxx) //your Local IP Server
#define Geo_DNS_SERVER IPAddress(xxx, xxx, xxx, xxx) //FRANKFURT
similar to project #1 but with another presentation
HARDWARE
before we continue the most important is to send our Rules to Tasmota Console and be sure they are acting as desired.
This project is also Stairs lights (Power1) will turn on if PIR detects a motion [PIR] Mode and lights will remain on for 30 sec. if PIR is triggered again before ruletimer1
( the countdown timer T1 ) finish the lights will remain on for another 30 sec and so on until there is no more movement .
Changing the [PIR] Mode switch to [TIMER] Mode will stop PIR from detecting motion and set the Timer for 180 sec (or 3 min) that you can change to your needs up to 9999 sec.
A Button to change Temperature from Celsius to Fahrenheit .
Stairs lights can also be controlled by the SR04 ultrasonic sensor (Distance change)
The possibility to change the triggering distance by “Numeric Input Interface” and to stop the US sensor when needed.
Porch lights (Power2) turns OFF with sunrise and ON at sunset.
Porch lights Button will show actual sunrise and sunset time every Hour.
Turn ON / OFF OLED Display (Power3) from Blynk application .
PUSH BUTTON on GPIO0
teleperiod 60
in the Console MenuLast picture is for Console Menu showing Rule3 on one line before sending it to Tasmota
Rule3
on SR04#Distance<%var3% do backlog publish stairs/Distance {"Distance":%value%};power1 on; ruletimer2 60 endon on rules#timer=2 do power1 off endon
on SR04#Distance>%var3% do backlog publish stairs/Distance {"Distance":%value%} endon
meaning of Rule3
if ultrasonic distance is less than var3
(variable3) then publish stairs distance value, turn Power1
on,
wait 60
sec until countdown ruletimer2
or T2 finish then turn off Power1
.
else if ultrasonic distance is greater than variable3 publish stairs distance value then Blynk can display it in the application.
Power1
is Stairs Lights
Here ruletimer2
is fixed for 60
sec
var3
is the “Numeric Input Distance” set in Blynk app.
ButtonTopic 0
SetOption1 1
SetOption11 1
SetOption32 20
switchmode1 1
Rule2
on Switch1#state=1 do backlog event AutoMotion=%var2%; publish stairs/var2/state %var2% endon
on event#AutoMotion==1 do backlog power1 on; ruletimer1 %var1% endon on rules#timer=1 do power1 off endon
on event#AutoMotion==0 do backlog power1 on; ruletimer1 %var1% endon on rules#timer=1 do power1 off endon
on button1#state=3 do publish stairs/cmnd/power3 2 endon on button1#state=2 do publish stairs/cmnd/power2 2 endon
Rule2 1
Commands Explanation
ButtonTopic 0
: (default) To not use topics for buttons
SetOption1 1
: Allow only single, double and hold press button actions
SetOption11 1
: Swap button single and double press functionality
SetOption32 20
: Set key hold time from 0.1 to 10 seconds (20 = 2 seconds)
SwitchMode1 1
: Will make Switch1#state to be 1 when PIR is ON and 0 when OFF
PIR output is connected to GPIO14 or D5 (Switch1n (82))
Rule2 1
: To enable rule 2
Commands are sent like Rules and are also stored in flash.
BUTTON WITH 3 DIFFERENT ACTIONS
on button1#state=3 do publish stairs/cmnd/power3 2 endon on button1#state=2 do publish stairs/cmnd/power2 2 endon
on button1#state=3
: When holding the button1 for 2 seconds it will toggle Power3 ( OLED on/off)
(state = 3 means HOLD)
on button1#state=2
: When you double press button1 it will toggle Power2 (Porch Lights)
(state = 2 means TOGGLE)
On button1 single press the Light in the Staircase will switch on/off.
Rule1
on switch1#state do publish stairs/PIR_stairs/state %value% endon
on Time#Set do publish stairs/sunset/state {"Sunset":%sunset%} endon
on Time#Set do publish stairs/sunrise/state {"Sunrise":%sunrise%} endon
on power3#state do publish stairs/sunset/state {"Sunset":%sunset%} endon
on power3#state do publish stairs/sunrise/state {"Sunrise":%sunrise%} endon
Rule1 1
Rule1 Explanation
SwitchMode1 1
on switch1#state do publish stairs/PIR_stairs/state %value% endon
This mean we will get a 1 if PIR detect a motion and 0 when PIR is in the OFF state.
Tasmota will publish this to Blynk , then Blynk will show a BLUE dot near the PIR label to indicate it is ON.
on Time#Set do publish stairs/sunset/state {"Sunset":%sunset%} endon
on Time#Set do publish stairs/sunrise/state {"Sunrise":%sunrise%} endon
Here I am using the “TIME” to Trigger the Event but you can use any Trigger from the Rule page.
Tasmota will publish every hour when NTP makes time in sync
to Blynk and it will be shown as a label of Power2 ( Porch Lights)
Edited : I add that if you press Power3 OLED display button, Sunrise and Sunset will be updated instantly (you don’t need to wait 60 min to get your update)
Trigger | Description | Version Introduced |
---|---|---|
Time#Initialized | once when NTP is initialized and time is in sync | |
Time#Initialized>120 | once when NTP is initialized and time is in sync after 02:00 | 6.1.0 |
Time#Set | every hour when NTP makes time in sync | **** |
Time#Minute | every minute | |
Time#Minute==241 | every day once at 04:01 (241 minutes after midnight) | 6.1.0 |
Time#Minute!5 | every five minutes |
timezone 1
Latitude 51.5074
Longitude 0.1278
timezone 2
Latitude 48.8566
Longitude 2.3522
timezone 2
Latitude 40.4168
Longitude 3.7038
also if you need to adjust summer time automatically read Here (TimeSTD
TimeDST)
or
Command | Parameters |
---|---|
Timezone |
-13..13 = set timezone |
99 = use timezone configured with TimeDST and TimeSTD
|
|
TimeSTD TimeDST | Set standard (STD) and daylight saving (DST) timezones |
0 = reset timezone parameters to firmware defaults |
|
H , W , M , D , h , T
|
|
H = hemisphere ( 0 = northern hemisphere / 1 = southern hemisphere) |
|
W = week ( 0 = last week of month, 1..4 = first … fourth) |
|
M = month ( 1..12 ) |
|
D = day of week ( 1..7 1 = sunday 7 = saturday) |
|
h = hour ( 0..23 ) |
|
T = timezone ( -780..780 ) (offset from UTC in MINUTES - 780min/60min=13hrs) |
|
Example: TIMEDST 1,1,10,1,2,660
|
These are Rules you may like to use instead of mine.
Using Timers, you can be set to turn on and off a light for illuminate a street/patio by night. But if the
Device has no power at the trigger time, then, when it powers up, the light will be off all night. So, as a failsafe, can be implemented a conditional control to be checked at device Startup with rules.
Set Timers to turn on your light at Sunset and Turn off at sunrise.
Use poweronstate 0
in order to start with lights off when powering up your device.
Set the following rules:
on Time#Initialized do backlog event checksunrise=%time%; event checksunset=%time% endon
on event#checksunset>%sunset% do power1 1 endon
on event#checksunrise<%sunrise% do power1 1 endon
The previous rules are conditionals that represent the following logic:
IF %time%>%sunset% DO Power1 ON also IF %time%<%sunrise% DO Power1 ON
Hardware :
Commands:
SwitchMode1 1
Rule1
on Switch1#state=1 do backlog event checksunrise=%time%; event checksunset=%time% endon
on event#checksunrise<%sunrise% do power1 1 endon
on event#checksunset>%sunset% do power1 1 endon
Rule1 1
All Commands and Rules you must send through Tasmota Console for Blynk to work correctly.
switchmode1 1
ButtonTopic 0
SetOption1 1
SetOption11 1
SetOption32 20
Rule1
on switch1#state do publish stairs/PIR_stairs/state %value% endon
on Time#Set do publish stairs/sunset/state {"Sunset":%sunset%} endon
on Time#Set do publish stairs/sunrise/state {"Sunrise":%sunrise%} endon
Rule2
on Switch1#state=1 do backlog event AutoMotion=%var2%; publish stairs/var2/state %var2% endon
on event#AutoMotion==1 do backlog power1 on; ruletimer1 %var1% endon on rules#timer=1 do power1 off endon
on event#AutoMotion==0 do backlog power1 on; ruletimer1 %var1% endon on rules#timer=1 do power1 off endon
on button1#state=3 do publish stairs/cmnd/power3 2 endon on button1#state=2 do publish stairs/cmnd/power2 2 endon
Rule3
on SR04#Distance<%var3% do backlog publish stairs/Distance {"Distance":%value%};power1 on; ruletimer2 60 endon on rules#timer=2 do power1 off endon
on SR04#Distance>%var3% do backlog publish stairs/Distance {"Distance":%value%} endon
To enable Rules 1, 2, 3 we send
Rule1 1
Rule2 1
Rule3 1
to stop a Rule from working we send a “0”
like
Rule3 0
NODE_MQTT_PIR_TEMP_TIMER.ino
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <BlynkSimpleEsp8266.h>
// #define BLYNK_PRINT Serial // Comment this to disable prints and save space
#include "Settings.h"
#include "mqtt_publish.h"
#include "mqtt_subscribe.h"
#include "wifi_credentials.h"
/*-------------------------------- Setup -------------------------------------*/
void setup() {
WiFi.mode(WIFI_STA);
Serial.begin(115200); // See the connection status in Serial Monitor
Serial.println(F("\n Setup STARTING"));
WiFi.begin(WIFI_SSID, WIFI_PASS);
if(WiFi.status() == 6) Serial.println("\tWiFi not connected yet.");
client.setServer(MQTT_SERVER, 1883);
client.setCallback(callback);
//----------------------------------Blynk------------------------------------
#ifdef LOCAL_SERVER
Blynk.config(AUTH, LOCAL_SERVER ,8080);
#else
Blynk.config(AUTH, Geo_DNS_SERVER);
#endif
while (Blynk.connect() == false) { // Wait until connected
if ((millis() - last_UP_change) > 30000) { // 30s before reset
Serial.println(F("resetting"));
ESP.reset();
}
}
//-----------------------------------OTA--------------------------------------
ArduinoOTA.setHostname(OTA_HOSTNAME);
// ArduinoOTA.setPassword(OTA_PASSWORD); //If you need a Password uncomment this line
ArduinoOTA.begin();
Serial.println(F(" Entering loop"));
timer.setInterval(4000L, Heartbeat); // Heartbeat 4000L
Blynk.syncVirtual(vPIN_ON_OFF_1);
Blynk.syncVirtual(vPIN_ON_OFF_2);
Blynk.syncVirtual(vPIN_ON_OFF_3);
Blynk.syncVirtual(vPIN_PIR_TIMER); // var2
Blynk.syncVirtual(vPIN_NUMERIC_TIMER); // var1
Blynk.syncVirtual(vPIN_NUMERIC_DISTANCE); // var3
Blynk.setProperty(vPIN_HEARTBEAT, "label", String("\xF0\x9F\x92\x93") + " HEARTBEAT");
}
/*----------------------------------Loop--------------------------------------*/
void loop() {
Blynk.run();
if(!Blynk.connected()) {
Serial.println(F("Resetting in loop"));
ESP.restart();
}
timer.run();
if (!client.connected()) {
reconnect();
}
client.loop();
ArduinoOTA.handle();
}
/*============================================================================*/
Settings.h
/*****************************************************************************
*
* Settings.h
*
*****************************************************************************/
BlynkTimer timer;
/*---------------------------Blynk Auth Code----------------------------------*/
#define AUTH "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
/*-------------------------Over The Air Hostname------------------------------*/
#define OTA_HOSTNAME "N-MQTT_Bridge" // put here your host name
#define OTA_PASSWORD "blynk" // your password for OTA if needed
/*----------------------------Hardware Pins-----------------------------------*/
/*-NodeMCU#*/
/*-------------------------------Virtual Pins---------------------------------*/
#define vPIN_HEARTBEAT V0
#define vPIN_SR04_DIST V8
#define vPIN_TEMP_UNIT V9
#define vPIN_ALL_TEMP V10
#define vPIN_ON_OFF_1 V21 // ON/OFF POWER 1
#define vPIN_PIR_TIMER V22 // select PIR motion or TIMER
#define vPIN_NUMERIC_TIMER V23 // up to 9999 sec
#define vPIN_AUTO_SR04 V25 // Activate/Desactivate Rule3
#define vPIN_TIMER_START V26 // PB START Timer
#define vPIN_NUMERIC_DISTANCE V27 // up to 300 cm
#define vPIN_ON_OFF_2 V31 // ON/OFF POWER 2 Activated by Sun
#define vPIN_ON_OFF_3 V41 // ON/OFF POWER 3 Turn ON/OFF I2C OLED
/*-----------------------------variables-------------------------------------*/
bool var2 ;
int var1 ;
int var3 ;
int counter = 0;
long int last_UP_change = millis();
int rssi;
float Vcc;
float Distance;
String SUNRISE;
String SUNSET;
/*---------------------------------Heartbeat--------------------------------*/
void Heartbeat() {
Blynk.virtualWrite(vPIN_HEARTBEAT," \xF0\x9F\x92\x96"); //
timer.setTimeout(2000L,[](){Blynk.virtualWrite(vPIN_HEARTBEAT," \xF0\x9F\x92\x97");});
}
/*--------------------------------------------------------------------------*/
mqtt_publish.h
/******************************************************************************
*
* mqtt_publish.h
*
*****************************************************************************/
WiFiClient espClient;
PubSubClient client(espClient);
//----------------------------------------------℃/℉----------------------------------------
BLYNK_WRITE(vPIN_TEMP_UNIT) { // Change Temp. Unit from Celsius ℃ to Fahrenheit ℉
if (param.asInt()) {
client.publish("stairs/cmnd/setoption8","0"); // Celcius ℃
delay(4000);
client.publish("stairs/cmnd/teleperiod", "300"); // to get sensor & state info
Blynk.setProperty(vPIN_TEMP_UNIT,"onLabel" ,String("\xf0\x9f\x8c\xa1") + " Celsius ℃ ");
Blynk.setProperty(vPIN_TEMP_UNIT,"onColor","#FFFFFF"); // White
Blynk.setProperty(vPIN_TEMP_UNIT,"onBackColor","#8a2be2"); // Blue Violet
Blynk.setProperty (vPIN_ALL_TEMP,"color","#8a2be2"); // Blue Violet
} else {
client.publish("stairs/cmnd/setoption8","1"); // Fahrenheit ℉
delay(4000);
client.publish("stairs/cmnd/teleperiod", "300"); // to get sensor & state info immediately
Blynk.setProperty(vPIN_TEMP_UNIT,"offLabel",String("\xf0\x9f\x8c\xa1") + " Fahrenheit ℉ ");
Blynk.setProperty(vPIN_TEMP_UNIT,"offColor","#04C0F8"); // BLYNK_BLUE
Blynk.setProperty(vPIN_TEMP_UNIT,"offBackColor","#04C0F8"); // BLYNK_BLUE
Blynk.setProperty (vPIN_ALL_TEMP,"color","#04C0F8"); // BLYNK_BLUE
}
}
//--------------------------------------------POWER1----(ON/OFF)------------------------------
BLYNK_WRITE(vPIN_ON_OFF_1) { // ON/OFF switch
if (param.asInt()) {
client.publish("stairs/cmnd/POWER1","1");
} else {
client.publish("stairs/cmnd/POWER1","0");
}
}
//---------------------------------------------POWER1----(PIR & Timer)------------------------
BLYNK_WRITE(vPIN_PIR_TIMER) { // PIR/TIMER
if (param.asInt()) {
client.publish("stairs/cmnd/switchmode1","1");
client.publish("stairs/cmnd/var1","30");
client.publish("stairs/cmnd/var2","1");
var1 = 30;
Blynk.setProperty(vPIN_PIR_TIMER,"label"," PIR " );
Blynk.setProperty(vPIN_PIR_TIMER,"onLabel",String("\xF0\x9F\x8F\x83"));
Blynk.setProperty(vPIN_PIR_TIMER,"onColor","#FFFFFF"); // White
Blynk.setProperty(vPIN_PIR_TIMER,"onBackColor","#04C0F8"); // BLYNK_BLUE
Blynk.setProperty(vPIN_NUMERIC_TIMER,"color","#04C0F8"); // BLYNK_BLUE
Blynk.virtualWrite(vPIN_NUMERIC_TIMER,var1);
Blynk.setProperty(vPIN_NUMERIC_TIMER,"label",String("\xE2\x8F\xB3")+" TIMER "+ 30 +String(" S"));
Blynk.setProperty(vPIN_TIMER_START,"label"," " );
Blynk.setProperty(vPIN_TIMER_START,"offLabel"," ");
Blynk.setProperty(vPIN_TIMER_START,"offColor","#FFFFFF"); // White
Blynk.setProperty(vPIN_TIMER_START,"offBackColor","#FFFFFF"); // White
var2 = 1;
} else {
client.publish("stairs/cmnd/switchmode1","0");
client.publish("stairs/cmnd/var1","180");
client.publish("stairs/cmnd/var2","0");
var1 = 180;
Blynk.setProperty(vPIN_PIR_TIMER,"label",String("\xE2\x8F\xB0") + " TIMER");
Blynk.setProperty(vPIN_PIR_TIMER,"offLabel",String("\xE2\x8F\xB0"));
Blynk.setProperty(vPIN_PIR_TIMER,"offColor","#FFFF00"); // YELLOW
Blynk.setProperty(vPIN_PIR_TIMER,"offBackColor","#00FF00"); // GREEN
Blynk.setProperty(vPIN_NUMERIC_TIMER,"color","#23C48E"); // BLYNK_GREEN
Blynk.virtualWrite(vPIN_NUMERIC_TIMER,var1);
Blynk.setProperty(vPIN_NUMERIC_TIMER,"label",String("\xE2\x8F\xB3")+" TIMER "+ 180 +String(" S"));
Blynk.setProperty(vPIN_TIMER_START,"label"," Start PB" );
Blynk.setProperty(vPIN_TIMER_START,"offLabel","Start");
Blynk.setProperty(vPIN_TIMER_START,"offColor","#00FF00"); // GREEN
Blynk.setProperty(vPIN_TIMER_START,"offBackColor","#00FF00"); // GREEN
var2 = 0;
}
char value[4];
dtostrf(var1, 2, 0, value);
client.publish("stairs/cmnd/ruletimer1",value);
BLYNK_WRITE(vPIN_NUMERIC_TIMER);
}
BLYNK_WRITE(vPIN_NUMERIC_TIMER) { // TIMER 0-9999 Sec
int VALUE = param.asInt();
var1 = VALUE;
char value[4];
dtostrf(VALUE, 2, 0, value);
client.publish("stairs/cmnd/var1", value);
client.publish("stairs/cmnd/ruletimer1", value);
Blynk.virtualWrite(vPIN_NUMERIC_TIMER,var1);
Blynk.setProperty(vPIN_NUMERIC_TIMER,"label",String("\xE2\x8F\xB3")+" TIMER "+ var1 +String(" S"));
if (var2 == 1) {
client.publish("stairs/cmnd/POWER1", "ON");
}
}
BLYNK_WRITE(vPIN_TIMER_START) { // PB TIMER Sart
if (param.asInt()) {
if (var2 == 0){
char value[4];
dtostrf(var1, 2, 0, value);
client.publish("stairs/cmnd/ruletimer1",value);
client.publish("stairs/cmnd/POWER1","1");
} else {
client.publish("stairs/cmnd/POWER1","0");
}
}
}
//---------------------------------------------POWER2----(Sun)------------------------------
BLYNK_WRITE(vPIN_ON_OFF_2) { // ON/OFF PORCH Light
if (param.asInt()) {
client.publish("stairs/cmnd/POWER2","1");
} else {
client.publish("stairs/cmnd/POWER2","0");
Blynk.setProperty(vPIN_ON_OFF_2,"offColor","#8a2be2"); // Blue Violet
Blynk.setProperty(vPIN_ON_OFF_2,"offBackColor","#ffff00"); // YELLOW
}
}
//---------------------------------------------POWER3----(I2C OLED)----------------------
BLYNK_WRITE(vPIN_ON_OFF_3) { // ON/OFF I2C OLED
if (param.asInt()) {
client.publish("stairs/cmnd/POWER3","1");
} else {
client.publish("stairs/cmnd/POWER3","0");
}
}
//-----------------------------------------------SR04----------------------------------------
BLYNK_WRITE(vPIN_AUTO_SR04) { // AUTO/Manual
if (param.asInt()) {
client.publish("stairs/cmnd/Rule3","1");
Blynk.setProperty(vPIN_AUTO_SR04, "label",String("\xF0\x9F\x92\xAB") + " AUTO SR04");
} else {
client.publish("stairs/cmnd/Rule3","0");
client.publish("stairs/cmnd/POWER1","0");
Blynk.virtualWrite(vPIN_SR04_DIST,"--.--");
Blynk.setProperty (vPIN_AUTO_SR04, "label",String("\xE2\x9C\x8B") + " MANUAL SR04");
}
}
BLYNK_WRITE(vPIN_NUMERIC_DISTANCE) { //
int VALUE = param.asInt();
var3 = VALUE;
char value[4];
dtostrf(VALUE, 2, 0, value);
client.publish("stairs/cmnd/var3", value);
}
//------------------------------------------------------------------------------------------
mqtt_subscribe.h
/*******************************************************************************
*
* mqtt_subscribe.h
*
******************************************************************************/
#define MQTT_SERVER IPAddress(192,168,xxx,xxx) // Your MQTT Broker IP address
#define MQTT_USERNAME "xxxx" // put here your MQTT username
#define MQTT_PASSWORD "xxxx" // put here your MQTT password
#define InTOPIC_0 "stairs/tele/STATE"
#define InTOPIC_1 "stairs/tele/SENSOR"
#define InTOPIC_2 "stairs/PIR_stairs/state"
#define InTOPIC_3 "stairs/stat/POWER1"
#define InTOPIC_4 "stairs/stat/POWER2"
#define InTOPIC_5 "stairs/stat/POWER3"
#define InTOPIC_6 "stairs/stat/RESULT"
#define InTOPIC_7 "stairs/sunset/state"
#define InTOPIC_8 "stairs/sunrise/state"
#define InTOPIC_9 "stairs/Distance"
void reconnect() { // Loop until we're reconnected
while (!client.connected()) {
Serial.print(" Attempting MQTT connection..."); // Attempt to connect
delay(4000);
if (client.connect("DEVS", MQTT_USERNAME, MQTT_PASSWORD)) {
Serial.println("connected");
counter = 0; // ... and resubscribe
client.subscribe(InTOPIC_0);
client.subscribe(InTOPIC_1);
client.subscribe(InTOPIC_2);
client.subscribe(InTOPIC_3);
client.subscribe(InTOPIC_4);
client.subscribe(InTOPIC_5);
client.subscribe(InTOPIC_6);
client.subscribe(InTOPIC_7);
client.subscribe(InTOPIC_8);
client.subscribe(InTOPIC_9);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 4 second");
++counter;
if (counter > 20) ESP.restart(); // Wait 4 seconds before retrying
}
}
}
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();
//-------------------------------------------STATE--------------------------------------------
// MQT: stairs/tele/STATE =
// {"Time":"2019-03-18T17:56:18","Uptime":"0T18:23:11","Vcc":3.002,"SleepMode":"Dynamic",
// "Sleep":50,"LoadAvg":19,"POWER1":"ON","POWER2":"OFF","Wifi":{"AP":1,"SSId":"BLYNK",
// "BSSId":"48:F8:B3:84:AB:22","Channel":10,"RSSI":84,"LinkCount":6,"Downtime":"0T00:00:21"}}
if (String(topic) == InTOPIC_0) { // stairs/tele/STATE
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
Vcc = root["Vcc"]; // 3.002
rssi = root["Wifi"]["RSSI"]; // 84
const char* Uptime = root["Uptime"]; // 0T18:23:11
// const char* Time = root["Time"]; // 2019-03-18T17:56:18
// const char* SleepMode = root["SleepMode"];// Dynamic
// int Sleep = root["Sleep"]; // 50
// int LoadAvg = root["LoadAvg"]; // 19
// const char* POWER1 = root["POWER1"]; // ON
// const char* POWER2 = root["POWER2"]; // OFF
// int AP = root["Wifi"]["AP"]; // 1
// const char* SSId = root["Wifi"]["SSId"]; // BLYNK
// const char* BSSId = root["Wifi"]["BSSId"];// 48:F8:B3:84:AB:22
// int Chl = root["Wifi"]["Channel"];// 10
// int LC= root["Wifi"]["LinkCount"];// 6
// const char* DT = root["Wifi"]["Downtime"];// 0T00:00:21
Blynk.setProperty(vPIN_HEARTBEAT, "label",String("\xE2\x8F\xB3")+" "+String(Uptime));
//-------------------------------------------SENSOR-------------------------------------------
//MQT: stairs/tele/SENSOR =
//{"Time":"2019-03-19T13:19:16","Switch1":"OFF","DS18B20-1":{"Id":"000006F242B1","Temperature":21.9},
//"DS18B20-2":{"Id":"000006F2B80A","Temperature":22.0},"DS18B20-3":{"Id":"00000789E508","Temperature":21.9},
//"DS18B20-4":{"Id":"8000001F18D8","Temperature":22.6},"AM2301":{"Temperature":22.0,"Humidity":68.7},
//"ADS1115":[{"A0":-1,"A1":26033,"A2":4851,"A3":4809}],"SR04":{"Distance":40.509},"TempUnit":"C"}
}else if (String(topic) == InTOPIC_1) { // stairs/tele/SENSOR
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
const char* Time = root["Time"]; // 2019-03-19T13:19:16
float DS1_T = root["DS18B20-1"]["Temperature"]; // 21.9
float DS2_T = root["DS18B20-2"]["Temperature"]; // 22.0
float DS3_T = root["DS18B20-3"]["Temperature"]; // 21.9
float DS4_T = root["DS18B20-4"]["Temperature"]; // 22.6
float Temp = root["AM2301"]["Temperature"]; // 22.0
float Hum = root["AM2301"]["Humidity"]; // 68.7
float Dist = root["SR04"]["Distance"]; // 40.509
// const char* Switch1 = root["Switch1"]; // OFF
// const char* DS1_ID = root["DS18B20-1"]["Id"]; // 000006F242B1
// const char* DS2_ID = root["DS18B20-2"]["Id"]; // 000006F2B80A
// const char* DS3_ID = root["DS18B20-3"]["Id"]; // 00000789E508
// const char* DS4_ID = root["DS18B20-4"]["Id"]; // 8000001F18D8
// float ADS_A0 = root["ADS1115"]["A0"]; // -1
// float ADS_A1 = root["ADS1115"]["A1"]; // 26033
// float ADS_A2 = root["ADS1115"]["A2"]; // 4851
// float ADS_A3 = root["ADS1115"]["A3"]; // 4809
// const char* TU = root["TempUnit"];// "C"
Blynk.setProperty(vPIN_TEMP_UNIT, "label",String("\xE2\x8C\x9A")+Time+" "+String("\xF0\x9F\x93\xB6")+" WiFi = "+rssi+" %"+" "+String("\xE2\x9A\xA1")+"Vcc = "+String(Vcc,2)+" V" );
Blynk.virtualWrite(vPIN_ALL_TEMP, (String (DS1_T,1)+" "+String (DS2_T,1)+" "+String (DS3_T,1)+" "+String (Temp,1)+" "+String(Hum,1)+"%"));
Blynk.setProperty (vPIN_ALL_TEMP, "label",String("\xf0\x9f\x8c\xa1")+"DS18B20-1 DS18B20-2 DSPROBE-3 "+String("\xf0\x9f\x8c\xa1")+"AM2302"+" "+String("\xF0\x9F\x92\xA7")+"AM2302");
//--------------------------------------------PIR---------------------------------------------
}else if (String(topic) == InTOPIC_2) { // stairs/PIR_stairs/state = (1/0)
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
if ((char)payload[0] == '1') { // Switch1 on LED if 1 was received as first character
Serial.println("PIR = ON");
Blynk.setProperty(vPIN_PIR_TIMER,"label"," PIR " +String("\xF0\x9F\x94\xB5"));
}
if ((char)payload[0] == '0'){
Serial.println("PIR = OFF");
if (var2==1) {
Blynk.setProperty(vPIN_PIR_TIMER,"label", " PIR ");
Blynk.setProperty(vPIN_PIR_TIMER,"onLabel",String("\xF0\x9F\x8F\x83"));
Blynk.setProperty(vPIN_PIR_TIMER,"onColor","#FFFFFF"); // White
Blynk.setProperty(vPIN_PIR_TIMER,"onBackColor","#04C0F8"); // BLYNK_BLUE
}
if (var2==0) {
Blynk.setProperty(vPIN_PIR_TIMER,"label",String("\xE2\x8F\xB0") + " TIMER ");
Blynk.setProperty(vPIN_PIR_TIMER,"offLabel",String("\xE2\x8F\xB0"));
Blynk.setProperty(vPIN_PIR_TIMER,"offColor","#E0E000"); // dark YELLOW
Blynk.setProperty(vPIN_PIR_TIMER,"offBackColor","#23C48E"); // BLYNK_GREEN
}
}
//---------------------------------------------POWER1-----------------------------------------
}else if (String(topic) == InTOPIC_3) { // stairs/stat/POWER1
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
if ((char)payload[1] == 'N') {
Blynk.virtualWrite(vPIN_ON_OFF_1,1);
Serial.println("POWER1 = ON");
}else{
Blynk.virtualWrite(vPIN_ON_OFF_1,0);
Serial.println("POWER1 = OFF");
}
//---------------------------------------------POWER2-----------------------------------------
}else if (String(topic) == InTOPIC_4) { // stairs/stat/POWER2
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
if ((char)payload[1] == 'N') {
Blynk.virtualWrite(vPIN_ON_OFF_2,1);
Serial.println("POWER2 = ON");
}else{
Blynk.virtualWrite(vPIN_ON_OFF_2,0);
Serial.println("POWER2 = OFF");
}
//---------------------------------------------POWER3-----------------------------------------
}else if (String(topic) == InTOPIC_5) { // stairs/stat/POWER3
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
if ((char)payload[1] == 'N') {
Blynk.virtualWrite(vPIN_ON_OFF_3,1);
Serial.println("POWER3 = ON");
}else{
Blynk.virtualWrite(vPIN_ON_OFF_3,0);
Serial.println("POWER3 = OFF");
}
//--------------------------------------------------------------------------------------------
//09:59:13 MQT: stairs/stat/RESULT = {"T1":20,"T2":0,"T3":0,"T4":0,"T5":0,"T6":0,"T7":0,"T8":0}
//10:01:05 MQT: stairs/stat/RESULT = {"POWER1":"ON"}
//10:01:40 MQT: stairs/stat/RESULT = {"POWER1":"OFF"}
//10:04:11 MQT: stairs/stat/RESULT = {"var1":"20"}
}else if (String(topic) == InTOPIC_6) { //stairs/stat/RESULT
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
int var1 = root["var1"];
int T1 = root["T1"];
const char* POWER1 = root["POWER1"]; // "OFF"
//------------------------------------------------sunset--------------------------------------
}else if (String(topic) == InTOPIC_7) { //stairs/sunset/state
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
int mins = root["Sunset"];
int hours = mins / 60; //convert minutes to hours
mins = mins - (hours * 60); //subtract the coverted minutes to hours in order to display 59 minutes max
String mins_o = ":";
if (mins < 10) { mins_o = ":0";}
SUNSET = hours + mins_o + mins ;
//------------------------------------------------sunrise-------------------------------------
}else if (String(topic) == InTOPIC_8) { //stairs/sunrise/state
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
int mins = root["Sunrise"];
int hours = mins / 60; //convert minutes to hours
mins = mins - (hours * 60); //subtract the coverted minutes to hours in order to display 59 minutes max
String mins_o = ":";
if (mins < 10) { mins_o = ":0";}
SUNRISE = hours + mins_o + mins ;
// every Hour update Sunrise & Sunset [Tasmota => " on Time#Set do publish "]
Blynk.setProperty(vPIN_ON_OFF_2,"label"," [* PORCH LIGHT *] Sunrise @ "+SUNRISE + " "+"Sunset @ "+SUNSET);
Serial.print("SUNRISE @ ");Serial.print(SUNRISE);Serial.print(" ");Serial.print("SUNSET1 @ "); Serial.println(SUNSET);
//-------------------------------------------------SR04---------------------------------------
}else if (String(topic) == InTOPIC_9) { // stairs/Distance
StaticJsonBuffer<450> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((char*)payload);
Distance = root["Distance"];
Blynk.virtualWrite(vPIN_SR04_DIST,Distance);
Blynk.setProperty (vPIN_SR04_DIST, "label", "DISTANCE in Cm");
}
}
//--------------------------------------------------------------------------------------------
wifi_credentials.h
/*******************************************************************************
*
* wifi_credentials.h
*
******************************************************************************/
/*******************************************************************************
Local Blynk Server Settings (uncomment to use local server and set address)
*******************************************************************************/
#define WIFI_SSID "xxxx" // ["xxxx" PW = "xxxx" ]
#define WIFI_PASS "xxxx" //Set pass to "" for open networks.
//#define LOCAL_SERVER IPAddress(192, 168,xxx, xxx) //your Local IP Server
#define Geo_DNS_SERVER IPAddress(xxx, xxx, xxx, xxx) //FRANKFURT
1. SSD1306 OLED 128x32/128x64 (default addresses 0x3C
, 0x3D
)
First for our OLED to work you must uncomment the oled section in TASMOTA
my_user_config.h
before Building and Uploading
#define USE_DISPLAY // Add I2C Display Support (+2k code)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
#define USE_DISPLAY_LCD // [DisplayModel 1] Enable Lcd display (I2C addresses 0x27 and 0x3F) (+6k code)
#define USE_DISPLAY_SSD1306 // [DisplayModel 2] Enable SSD1306 Oled 128x64 display (I2C addresses 0x3C and 0x3D) (+16k code)
#define USE_DISPLAY_MATRIX // [DisplayModel 3] Enable 8x8 Matrix display (I2C adresseses see below) (+11k code)
#define MTX_ADDRESS1 0x71 // [DisplayAddress1] I2C address of first 8x8 matrix module
#define MTX_ADDRESS2 0x74 // [DisplayAddress2] I2C address of second 8x8 matrix module
#define MTX_ADDRESS3 0x75 // [DisplayAddress3] I2C address of third 8x8 matrix module
#define MTX_ADDRESS4 0x72 // [DisplayAddress4] I2C address of fourth 8x8 matrix module
#define MTX_ADDRESS5 0x73 // [DisplayAddress5] I2C address of fifth 8x8 matrix module
#define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module
#define MTX_ADDRESS7 0x00 //[DisplayAddress7] I2C address of seventh 8x8 matrix module
#define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module
#endif // USE_I2C
My OLED Display settings
Backlog DisplayMode 2; DisplayModel 2; DisplayCols 22; DisplayRows 8
02:24:07 CMD: Display
02:24:07 MQT: stairs/stat/RESULT = {"Display":{"Model":2,"Mode":2,"Dimmer":1,"Size":1,"Font":1,"Rotate":0,"Refresh":2,"Cols":[22,8],"Rows":8}}
Command | Parameters |
---|---|
Display | Show current display setting as JSON string |
DisplayAddress |
0..255 = set display module address |
DisplayDimmer |
0 = switch the display off |
1..100 = switch the display on |
|
0..100 = set display luminosity (only on 8x8 Dot-Matrix displays)
|
|
DisplayMode |
0..5 = set to display predefined content according to display type |
DisplayModel | Set model of your display: |
1 = I2C LCD Display (default addresses 0x27 , 0x3F ) |
|
2 = SSD1306 OLED 128x32/128x64 (default addresses 0x3C , 0x3D ) |
|
3 = 8x8 Dot-Matrix |
|
4 = ILI9341 TFT LCD |
|
5 = E-Paper Display |
|
DisplayRefresh |
1..7 = set time in seconds to update predefined content when using DisplayMode ≠ 0
|
DisplaySize |
1..4 = set display scale-up size (only for DisplayModel 2 (SSD1306 OLED) and DisplayModel 4 (ILI9341 TFT LCD)) |
DisplayRotate | Set rotation angle |
0 = 0° |
|
1 = 90° |
|
2 = 180° |
|
3 = 270° |
|
DisplayText |
<value> = for a full guide see DisplayText use
|
DisplayCols |
1..44 = set number of display columns |
DisplayRows |
1..32 = set number of display rows |
DisplayFont | (reserved command, currently unsupported) |
The display driver is able to display predefined setups of text or user defined text. To display text using DisplayText
set DisplayMode
to 0
(also 1
for DisplayModel 3
(Dot-Matrix)).
Parameter | LCD Display | OLED Display | TFT Display |
---|---|---|---|
0 | DisplayText | DisplayText | DisplayText |
1 | Time/Date | Time/Date | Time/Date |
2 | Local sensors | Local sensors | Local sensors |
3 | MQTT and Time/Date | Local sensors and Time/Date | Local sensors and Time/Date |
4 | Local sensors | MQTT and local sensors | MQTT and local sensors |
5 | MQTT and Time/Date | MQTT, local sensors and Time/Date | MQTT, local sensors and Time/Date |
0x27
, 0x3F
)If LCD is enabled in TASMOTA
my_user_config.h
and you don’t see any character on your screen.
check the DisplayAddress
for 0x27
or 0x3F
if it is not, you can correct it by sending the correct address.
Command : DisplayAddress 0x3F
in HEX or DisplayAddress 63
in DECIMAL (both works)
My LCD Display settings
11:18:39 CMD: display
11:18:39 MQT: stairs/stat/RESULT = {"Display":{"Model":1,"Mode":1,"Dimmer":1,"Size":1,"Font":1,"Rotate":0,"Refresh":2,"Cols":[16,8],"Rows":2}}
Command: I2CScan
More DISPLAYS ca be Found HERE
The functionality described here is expected to be merged from PR 3748
The DisplayText
command is used to display text as well as graphics and graphs on LCD, OLED and e-Paper displays. The command argument is a string that is printed on the display at the current position. The string can be prefixed by embedded control commands enclosed in brackets []
.
In order to use the DisplayText
command the DisplayMode
must be set to 0
(or optional 1
on LCD displays) or other modes must be disabled before compilation with #undef USE_DISPLAY_MODES1TO5
.
In the list below _p_
stands for parameter and may be a number from 1 to n digits. On monochrome graphic displays things are drawn into a local frame buffer and sent to the display either via the d
command or automatically at the end of the command.
l _p_
= sets a character line to print at (on LCD display p = {0…}, on TFT display p = {1…})
c _p_
= sets a character column to print at (on LCD display p = {0…}, on TFT display p = {1…})
x _p_
= sets the x position for consecutive prints
y _p_
= sets the y position for consecutive prints
Text is printed at the last provided position, either l or y for the vertical position, and either x or x for the horizontal position. Neither x nor y are advanced/updated after printing text.
h _p_
= draws a horizontal line with length p (x is advanced)
v _p_
= draws a vertical line with length p (y is advanced)
L _p_:_p_
= draws a line to p : p (x,y are advanced)
k _p_
= draws a circle with radius p
K _p_
= draws a filled circle with radius p
r _p_:_p_
= draws a rectangle with p with and p height
R _p_:_p_
= draws a filled rectangle with p with and p height
z
= clear the display
i
= (re)init the display (in e-Paper mode with partial update)
I
= (re)init the display (in e-Paper mode with full update)
d
= update the display
D _p_
= switch display auto updates on( p =1)/off( p =0), when off display must be updated with d
o
= switch display off
O
= switch display on
t
= display Tasmota time in HH:MM
T
= display Tasmota date in DD.MM.YY
s _p_
= set text scaling for classic GFX font (scaling factor 1…N)
f _p_
= set font (1=12, 2=24,(opt 3=8)) if font==0 the classic GFX font is used
C _p_
= set color (0,1) for black or white (later for color displays index colors)
E-Paper displays have 2 operating modes: full update and partial update. While full update delivers a clean and sharp picture it has the disadvantage of taking several seconds for the screen update and shows severe flickering during update. Partial update is quite fast (300 ms) with no flickering but there is the possibility that erased content is still slightly visible. To “whiten” the display it is therefore useful to perform a full update in regular intervals (e.g each hour).
Defines => USE_SOFTSPI, USE_DISPLAY_EPAPER29, USE_DISPLAY_EPAPER42
I2C displays are connected in the usual manner and defined via Tasmota pin selection. The I2C Adress must be given by DisplayAddress XX
, e.g. 60, and the model set with DisplayModel
,e.g. 2 for SSD1306. To permanently turn the display on set DisplayDimmer 100
. Display rotation can be permanently set using DisplayRotate X
(x = 0..3
).
E-Paper displays are connected via 3 wire SPI (CS, SCLK, MOSI) the other 3 Interface lines of the display (DC, Reset, busy) may be left unconnected. The jumper on the circuit board of the display must be set to 3 wire SPI.
Print Text at size 1 on line 1, column 1:
DisplayText [s1l1c1]Hello how are you?
Draw a rectangle and draw text inside with size 2 and 7 chars padded with spaces:
DisplayText [x85y95h130v30h-130v-30s2p7x90y100]37.25 C
Clear screen:
DisplayText [z]
Draw rectangle from x,y with width and height:
DisplayText [x50y50r200:100]
Show sensor values, time and a separation line, whiten display every 60 minutes (line breaks and indentation added for readability):
rule1 on tele-SHT3X-0x44#Temperature do DisplayText [f1p7x0y5]%value% C endon
on tele-SHT3X-0x44#Humidity do DisplayText [f1p10x70y5]%value% %[x0y20h296x250y5t] endon
on tele-BMP280#Pressure do DisplayText [f1p10x140y5]%value% hPa endon
on Time#Minute|60 do DisplayText [Tt] endon
Show 4 analog channels (line breaks and indentation added for readability):
rule1 on tele-ADS1115#A0 do DisplayText [s1p21c1l01]Analog1: %value% adc endon
on tele-ADS1115#A1 do DisplayText [s1p21c1l3]Analog2: %value% adc endon
on tele-ADS1115#A2 do DisplayText [s1p21c1l5]Analog3: %value% adc endon
on tele-ADS1115#A3 do DisplayText [s1p21c1l7]Analog4: %value% adc endon
Show BME280 + SGP30 (line breaks and indentation added for readability):
rule1 on tele-BME280#Temperature do DisplayText [s1p21x0y0]Temp: %value% C endon
on tele-BME280#Humidity do DisplayText [s1p21x0y10]Hum : %value% %% endon
on BME280#Pressure do DisplayText [s1p21x0y20]Prss: %value% hPa endon
on tele-SGP30#TVOC do DisplayText [s1p21x0y30]TVOC: %value% ppb endon
on tele-SGP30#eCO2 do DisplayText [s1p21x0y40]eCO2: %value% ppm [s1p0x0y50]Time: [x35y50t] endon
Waveshare has 2 kinds of display controllers: with partial update and without partial update. The 2.9 inch driver is for partial update and should support also other Waveshare partial update models with modified WIDTH and HEIGHT parameters. The 4.2 inch driver is a hack which makes the full update display behave like a partial update and should probably work with other full update displays.
The drivers are sub classes of the Adafruit GFX library. The class hierarchy is LOWLEVEL :: Paint :: Renderer :: GFX
, where: GFX
: unmodified Adafruit library Renderer
: the interface for Tasmota Paint
: the modified pixel driver for e-paper
LOWLEVEL
.The display dispatcher only does the class init call. All other calls go to the Renderer
class.
In black and white displays a local ram buffer must be allocated before calling the driver. This must be set to zero on character or TFT color displays.
To use the 400x300 e-Paper display the Arduino library 2.4 or later must be used because it leaves much more RAM available than prior versions. This display requires 15k of RAM!
About 28 k flash is used by these 4 drivers, the epd fonts use about 9k space, which can be if-def’d.
Details are in this link: