ITСooky

IT-рецепты съедобные и не очень!

IoT совсем по-взрослому: Свои устройства на esp8266 с управлением через Node-Red

дата 15.03.2019

Одной статьи про Node-Red мне оказалось мало, почувствовал что он может больше.. но как. Простота его и мешает и помогает. Быстрота развертывания точно помогает особенно для тестирования скриптов для esp8266. И так ставлю задачу сделать банальный погодный модуль — качество воздуха, влажность, температура и вынести его на улицу, а так же умная управляемая розетка — тоже банально но сложновато — например для сохранения настроек приходилось зеленое конвертировать в круглое и писать в память esp8266 которой на самом деле нет!!!


Подробно про Node-Red писать не буду, было описано раньше — он установлен работает, также стоят доп модуле moments и dashboard.

В NR также должны быть кирпичи задающие переменную дату времени — вот она. Нужна для записи данных датчиков в файл нужна во всех схемах.

[{"id":"d1f915cf.6b6728","type":"inject","z":"e60c0f81.64c18","name":"","topic":"","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":1300,"wires":[["3292d870.1e3dd8"]]},{"id":"3292d870.1e3dd8","type":"moment","z":"e60c0f81.64c18","name":"","topic":"","input":"","inputType":"msg","inTz":"Europe/Moscow","adjAmount":"3","adjType":"hours","adjDir":"add","format":"","locale":"en_US","output":"time","outputType":"flow","outTz":"Europe/Moscow","x":400,"y":1300,"wires":[[]]}]

Кстати Node-Red легко убивает посылкой в цикле без тормозов данных по MQQT с esp8266, не надо так делать.

Погодный модуль
Для этого модуля я взял из предыдущей статьи NodeMcu V3 LoLin, датчик температуры DHT22, и MQ-135
Схема соединения

Собрал вот такой бутерброд

У DHT22 тонкие ножки, пришлось пистолетом приклееть, у MQ135 лучше но тоже приелеел — та еще шильда получилось

Датчик mq135 живет своей жизнью, показания зависит от хрен знает чего. Подключен он к 5v на ESP8266, показывает 17 попугаев, если туда же в 5v подключить датчик температуры то mq135 начинает показывать 500 попугаев, если датчик температуры подключить к 3.3v то мку показывает 61 попугаев. На то он и аналоговый.

Так же важно понимать что датчику нужно разогреваться. При первом включение 48 часов, потом при кратковременной потере питания минут 10 он в себя приходит. И может не вернуться у меня с 480 прыгнул на 200 и не вернулся!

Вообще то он называется датчиком качества воздуха, и точность его измерения в двух позициях Хороший-Плохой. И это касается именно воздуха на улице, в квартире он плохой воздух не улавливает, как я не старался…(только если в рот засунуть) А вот на улице дым, может бензин, спирт(да у нас та еще улица) это улавливает!

Если использовать к этому датчики библиотеку и откалибровать то можно получать значение похожее на настоящие попугаи в ppm — содержание угликислого газа в воздухе. Точно для нас не важно, потому что её и не будет с таким датчиком, главное что до 350 ppm это отлично для улицы, до 800 в помещении — вот тут все описано с настоящим прибором https://habr.com/company/tion/blog/389097/

Калибровать надо в окончательной сборке, а то добавление других датчиков влияет на результаты аналогового вывода(почему-то) да и просто в макетке совсем другие показания.
Делаю по этой инструции https://hackaday.io/project/3475-sniffing-trinket/log/12363-mq135-arduino-library

В mq135.h который, после установки библиотеки лежит у меня в /home/myusername/snap/arduino-mhall119/5/Arduino/libraries/MQ135-master в Ubuntu надо поменять значение резистора, я решил что он у меня 1, по умолчанию 10 об этом говорят другие датчикоиспытатели вот тут https://mysku.ru/blog/aliexpress/41409.html

/// The load resistance on the board
#define RLOAD 1.0

запускаю вот такой код и смотрю 
#include <MQ135.h> 
#define analogPin A0
MQ135 gasSensor = MQ135(analogPin);

void setup() {

  Serial.begin(9600); 
  delay(1000); 

}

void loop() {

 float rzero = gasSensor.getRZero(); // чтение калибровочных данных
 Serial.println(rzero); // выдача в последовательный порт

 delay(5000);
}

Выносим на улицу на пол часа, температуру улицы перед этим надо довести до 20 градусов, влажность говорят не так важна.

В мониторинг порта пишется значени е его встаялеми в тот же файле, доводим строку до вида

#define RZERO 567.63

После этого датчик мне выдает 682 попугаев в помещении — похоже на настоящее значение. Да и значения меняются с большим шагом сразу на сотни…

Датчик dht22, ну про него все ясно и известно давно — вот только точность его я оцениваю в реальных условиях в плюс минус 1, а не 0,5.

Прошивка для esp8266 — просто посылает влажность, температуру, качество воздуха, статус питания, и соединение с MQQT сервером, единожды моргает в момент посылки данных светодиодом, долго когда нет связи, и позволяет через Node-Red менять интервал посылки данных.

Сам скрипт

#include <PubSubClient.h>
#include <DHT_U.h>
#include <DHT.h>
#include <ESP8266WiFi.h>
#include <MQ135.h>
#include <EEPROM.h>
 

// Uncomment one of the lines bellow for whatever DHT sensor type you're using!
//#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
#define LED_BUILTIN 2


// Change the credentials below, so your ESP8266 connects to your router
const char* ssid = "imyawifitochki";
const char* password = "parolevoyniy";
const char* mqttUser = "name";
const char* mqttPassword = "passworda";
const char* mqttTopicHumidity = "room0/humidity";
const char* mqttTopicTemperature = "room0/temperature";
const char* mqttTopicGas = "room0/gas";
const char* mqttTopicWifi = "room0/wifistatus";
const char* mqttTopicPower = "room0/powerstatus";


const char* mqttTopicResendTime = "room0/resendtime";
const char* mqttTopicResendTimeStatus = "room0/resendtimestatus";
unsigned long resendtime; 
long resendtimetemp; 

// Change the variable to your MQQT IP address, so it connects to your MQTT broker
const char* mqtt_server = "192.168.1.209";

// DHT Sensor - GPIO 5 = D1 on NodeMCU board
const int DHTPin = 5;

MQ135 gasSensor = MQ135(A0);


// Timers auxiliar variables
unsigned long now = millis();
unsigned long lastMeasure = 0;
float ppm;
boolean wifistatus = false;
boolean powerstatus = false;

// Initializes the espClient. You should change the espClient name if you have multiple ESPs running in your home automation system
WiFiClient espClient;
PubSubClient client(espClient);

// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);


void EEPROMWritelong(int address, long value)
      {
      //Decomposition from a long to 4 bytes by using bitshift.
      //One = Most significant -> Four = Least significant byte
      byte four = (value & 0xFF);
      byte three = ((value >> 8) & 0xFF);
      byte two = ((value >> 16) & 0xFF);
      byte one = ((value >> 24) & 0xFF);

      //Write the 4 bytes into the eeprom memory.
      EEPROM.write(address, four);
      EEPROM.commit();
      EEPROM.write(address + 1, three);
      EEPROM.commit();
      EEPROM.write(address + 2, two);
      EEPROM.commit();
      EEPROM.write(address + 3, one);
      EEPROM.commit();
      }

long EEPROMReadlong(long address)
      {
      //Read the 4 bytes from the eeprom memory.
      long four = EEPROM.read(address);
      long three = EEPROM.read(address + 1);
      long two = EEPROM.read(address + 2);
      long one = EEPROM.read(address + 3);

      //Return the recomposed long by using bitshift.
      return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
      }
      

void setup() {
  EEPROM.begin(8); 
  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  pinMode(LED_BUILTIN, OUTPUT); 
  resendtimetemp = EEPROMReadlong(1);
  resendtime = 1000 * resendtimetemp + 500;
  client.setCallback(callback);
}

void callback(String topic, byte* message, unsigned int length) {
  String messageTemp; 
  for (int i = 0; i < length; i++) {
   messageTemp += (char)message[i];
  };
  

 if(topic==mqttTopicResendTime){
resendtimetemp = messageTemp.toInt();
static char TimeResend[7];
    dtostrf(resendtimetemp, 6, 0, TimeResend);
client.publish(mqttTopicResendTimeStatus, TimeResend);
EEPROMWritelong(1, resendtimetemp);
resendtime = 1000 * resendtimetemp; 
delay(500);
 };
 

      
}
// DThis functions connects your ESP8266 to your router
void setup_wifi() {
  delay(10);  
  WiFi.begin(ssid, password);
}


// This functions reconnects your ESP8266 to your MQTT broker 
void reconnect() {
if (client.connect(WiFi.hostname().c_str(), mqttUser, mqttPassword)) {
 
  client.subscribe(mqttTopicResendTime);
  } else {
      // Wait 5 seconds before retrying
      delay(500);
    }
}


void loop() {

now = millis();

  //dont know what this string does, but without it all does not work
 if(!client.loop()) 
     client.connect("blabla");

   if (!client.connected()) {
   digitalWrite(LED_BUILTIN, LOW); 
    reconnect(); 
   digitalWrite(LED_BUILTIN, HIGH);   
     };
       
if (now - lastMeasure > resendtime) {
lastMeasure = now;
if (client.connected()) { 
    
    // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
    float h = dht.readHumidity();
    // Read temperature as Celsius (the default)
    float t = dht.readTemperature();
    // Computes temperature values in Celsius
    float hic = dht.computeHeatIndex(t, h, false);
    static char temperatureTemp[7];
    dtostrf(hic, 6, 1, temperatureTemp);   
    static char humidityTemp[7];
    dtostrf(h, 6, 1, humidityTemp);
    //mq135
    //SensorGas = analogRead(0);
    float ppm = gasSensor.getPPM();
    static char GasTemp[7];
    dtostrf(ppm, 6, 0, GasTemp);
    
    // Publishes values
   digitalWrite(LED_BUILTIN, LOW);
    if (!wifistatus)
        {
            client.publish(mqttTopicWifi, "0");
            wifistatus = true;
        } else {
            client.publish(mqttTopicWifi, "1"); 
     };
     if (!powerstatus)
        {
            client.publish(mqttTopicPower, "0");
            powerstatus = true;
        } else {
            client.publish(mqttTopicPower, "1"); 
     };
   client.publish(mqttTopicTemperature, temperatureTemp);
   client.publish(mqttTopicHumidity, humidityTemp);
   client.publish(mqttTopicGas, GasTemp);

static char TimeResend[7];
    dtostrf(resendtimetemp, 6, 0, TimeResend);
client.publish(mqttTopicResendTimeStatus, TimeResend);

   digitalWrite(LED_BUILTIN, HIGH);
    } else {
  wifistatus = false;
      };
  };
}

Библиотеки начале скрипта стандартные и из предыдущей статьи напомню:

Качаем библиотеку для сенсора температуры и влажности dht22 https://github.com/adafruit/DHT-sensor-library/archive/master.zip и вот эту тоже https://github.com/adafruit/Adafruit_Sensor/archive/master.zip Добавляем её в программу через меню Scretch > Include Library > Add .ZIP Library

Теперь про Node-Red за этот модуль у него отвечают следующие кирпичи

фото

И текстом со всеми настройками, можно добавить сразу в свой Node-Red через экспорт

[{"id":"66632934.7d2108","type":"ui_chart","z":"e60c0f81.64c18","name":"Temperature","group":"bc9278be.b3a778","order":2,"width":"0","height":"0","label":"Temperature","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#8e0911","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":610,"y":1440,"wires":[[],[]]},{"id":"dd1d964c.587a48","type":"mqtt in","z":"e60c0f81.64c18","name":"Temperature","topic":"room0/temperature","qos":"2","broker":"572eed08.5bb714","x":410,"y":1400,"wires":[["66632934.7d2108","e4fe9e7e.ad3bd","2642c360.3f098c"]]},{"id":"59b169c0.45d7c8","type":"file","z":"e60c0f81.64c18","name":"Write temp_room0.log","filename":"/root/iot_data/temp_room0.log","appendNewline":true,"createDir":false,"overwriteFile":"false","x":840,"y":1400,"wires":[[]]},{"id":"e4fe9e7e.ad3bd","type":"function","z":"e60c0f81.64c18","name":"Add time to data","func":"var timenow=flow.get('time');\nmsg.payload = timenow + ' '+ msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":1400,"wires":[["59b169c0.45d7c8"]]},{"id":"55dd3d19.1cb534","type":"mqtt in","z":"e60c0f81.64c18","name":"Humidity","topic":"room0/humidity","qos":"2","broker":"572eed08.5bb714","x":400,"y":1540,"wires":[["2204294a.0fe706","6601b62f.9280f8","5c8f1bbc.113754"]]},{"id":"5b4fb0e2.0fe7c","type":"file","z":"e60c0f81.64c18","name":"Write humi_room0.log","filename":"/root/iot_data/humi_room0.log","appendNewline":true,"createDir":false,"overwriteFile":"false","x":840,"y":1540,"wires":[[]]},{"id":"2204294a.0fe706","type":"function","z":"e60c0f81.64c18","name":"Add time to data","func":"var timenow=flow.get('time');\nmsg.payload = timenow + ' '+ msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":1540,"wires":[["5b4fb0e2.0fe7c"]]},{"id":"7f21c47e.cd05ec","type":"mqtt in","z":"e60c0f81.64c18","name":"MQQT 0 status","topic":"room0/wifistatus","qos":"2","broker":"572eed08.5bb714","x":420,"y":1780,"wires":[["64b4189d.f8b998"]]},{"id":"64b4189d.f8b998","type":"ui_chart","z":"e60c0f81.64c18","name":"MQQT status","group":"ee36947a.ec2f48","order":1,"width":0,"height":0,"label":"MQQT was lost at","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"1","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":true,"colors":["#000000","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#77090a","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":590,"y":1780,"wires":[[],[]]},{"id":"4e04c12d.74d74","type":"mqtt in","z":"e60c0f81.64c18","name":"Power","topic":"room0/powerstatus","qos":"2","broker":"572eed08.5bb714","x":390,"y":1840,"wires":[["da433eb8.d0b53"]]},{"id":"da433eb8.d0b53","type":"ui_chart","z":"e60c0f81.64c18","name":"Power","group":"ee36947a.ec2f48","order":2,"width":0,"height":0,"label":"Power was lost at","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"1","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":true,"colors":["#000000","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#680808","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":570,"y":1840,"wires":[[],[]]},{"id":"de1fc131.312c1","type":"mqtt in","z":"e60c0f81.64c18","name":"Air Quality","topic":"room0/gas","qos":"2","broker":"572eed08.5bb714","x":400,"y":1660,"wires":[["74651f53.e4a4","466ebb3f.6f3764","3cb75aee.0a3c16"]]},{"id":"74651f53.e4a4","type":"ui_chart","z":"e60c0f81.64c18","name":"Gas","group":"bc9278be.b3a778","order":6,"width":0,"height":0,"label":"Air Quality","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#24a516","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":570,"y":1700,"wires":[[],[]]},{"id":"6601b62f.9280f8","type":"ui_chart","z":"e60c0f81.64c18","name":"Humidity","group":"bc9278be.b3a778","order":4,"width":"0","height":"0","label":"Humidity","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#0971c1","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":600,"y":1580,"wires":[[],[]]},{"id":"f15544ba.4e3c58","type":"ui_slider","z":"e60c0f81.64c18","name":"","label":"slider","group":"1022d713.859ec9","order":2,"width":0,"height":0,"passthru":true,"outs":"end","topic":"room0/resendtime","min":"15","max":"600","step":"5","x":390,"y":1900,"wires":[["eb3a4359.710b3"]]},{"id":"eb3a4359.710b3","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"room0/resendtime","qos":"","retain":"","broker":"572eed08.5bb714","x":590,"y":1900,"wires":[]},{"id":"aa44d360.ad6e4","type":"mqtt in","z":"e60c0f81.64c18","name":"resend time","topic":"room0/resendtimestatus","qos":"2","broker":"572eed08.5bb714","x":410,"y":1960,"wires":[["20197ac3.af7b56"]]},{"id":"20197ac3.af7b56","type":"ui_text","z":"e60c0f81.64c18","group":"1022d713.859ec9","order":1,"width":0,"height":0,"name":"","label":"Weather sensors - send and check  data  every (seconds):","format":"{{msg.payload}}","layout":"col-center","x":750,"y":1960,"wires":[]},{"id":"2642c360.3f098c","type":"ui_text","z":"e60c0f81.64c18","group":"bc9278be.b3a778","order":1,"width":0,"height":0,"name":"","label":"Temperature now is","format":"{{msg.payload}}","layout":"row-center","x":630,"y":1480,"wires":[]},{"id":"5c8f1bbc.113754","type":"ui_text","z":"e60c0f81.64c18","group":"bc9278be.b3a778","order":3,"width":0,"height":0,"name":"","label":"Humidity now is ","format":"{{msg.payload}}","layout":"row-center","x":620,"y":1620,"wires":[]},{"id":"466ebb3f.6f3764","type":"ui_text","z":"e60c0f81.64c18","group":"bc9278be.b3a778","order":5,"width":0,"height":0,"name":"","label":"Air quality now is","format":"{{msg.payload}}","layout":"row-center","x":610,"y":1740,"wires":[]},{"id":"4571b392.d9b66c","type":"file","z":"e60c0f81.64c18","name":"Write air_room0.log","filename":"/root/iot_data/air_room0.log","appendNewline":true,"createDir":false,"overwriteFile":"false","x":830,"y":1660,"wires":[[]]},{"id":"3cb75aee.0a3c16","type":"function","z":"e60c0f81.64c18","name":"Add time to data","func":"var timenow=flow.get('time');\nmsg.payload = timenow + ' '+ msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":1660,"wires":[["4571b392.d9b66c"]]},{"id":"bc9278be.b3a778","type":"ui_group","z":"","name":"Weather Data","tab":"c5ac561a.7e8ef8","order":1,"disp":true,"width":"10","collapse":false},{"id":"572eed08.5bb714","type":"mqtt-broker","z":"","name":"Mosquitto Orange","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"ee36947a.ec2f48","type":"ui_group","z":"","name":"Weather Status","tab":"c5ac561a.7e8ef8","order":3,"disp":true,"width":"10","collapse":false},{"id":"1022d713.859ec9","type":"ui_group","z":"","name":"Weather Send/Check interval Settings","tab":"5d7f916a.3be03","order":4,"disp":true,"width":"6","collapse":false},{"id":"c5ac561a.7e8ef8","type":"ui_tab","z":"","name":"Weather","icon":"dashboard","order":2},{"id":"5d7f916a.3be03","type":"ui_tab","z":"","name":"Settings","icon":"dashboard","order":4}]

После импорта чего-нибудь не забывайте нажимать Deploy в NR

Эти кирпичи дают нам статистику за 24 часа во вкладке Weather в Node-Red UI

График Power показывает когда модуль был выключен или перезагружен — после его включения на графике будет провал. MQQT следит за статусом WiFi соединения, действует также на своем графике.

Так же во вкладке Settings в Node-Red UI появляется квадрат Weather Send/Check interval Settings он позволяет задавать интервал обновления, который сохраняется в памяти esp8266

ВАЖНО: При первом запуске после прошивки esp8266 надо задать в во вкладке Settings в Node-Red UI интервал обновления в квадрате Weather Send/Check interval Settings, иначе там может быть любая фигня, читает из пустого места в памяти, а он может быть не пустым после прошивки.

Теперь про питание. Хотел беспроводной зарядкой питать через стекло, к сожалению эта технология не так сильна реально только на 8 мм от базы передается электричество.

При купил вот такое 18650 Батарея щит V3 для Raspberry Pi WEMOS для Arduino Micro Тип usb-USB — ссылку давать не будут потому что покупать это не стоит. В задумке это должно работать как ИБП отключается питание включается батарее, включается питание батарея на заряд питание на прямую. В реале даже от батарее не всегда включается — китайцы не до конца докопировали, или оригинал был такой же… Питание припаял к 3v пинам, от USB большего вообще как ИБП не работает, от пинов иногда работает! Итого получился вот такой гамбургер

Кидаем его на улицу, в доме работает 22-24 часа, реальная мощность левого самсунговского аккумулятора 18650 1000 mAh мерял. Основной потребитель датчик воздух — должен очень много выжирать.

Модуль умная розетка с датчиком температуры и влажности

Вот так он выглядит, слепил из того что было в Леруа Мерлен

В качестве основы были выбраны две паркетные палки, склеены столярным клеем. Провода 2.5 миллиметра, клеммы Клемма Wago 5 разъемов под провода 26.6х14х5х20.5 мм, полиамид, 5 шт — тяжеловато в них провода входят и кажется в инструкции слишком сильно советуют залуплять их. Все с трудом влезло в Коробка распределительная 120х80х50 мм, IP5 — провода много места занимают, просверлил дырку, заклеил с одной стороны изолентой и залил клеевым пиcтолетом, получилось отличное окошко для светодиода. Розетка Schneider Electric Этюд с заземлением шторки цвет серый IP44 отличная розетка и сделана в России, их можно собрать несколько в ряд, есть где просунуть провода, жалко нельзя вращать крышку, только в одном положении так что мешается когда две рядом.

Вот схема. Реле такое уже не продают, но думаю они все одинаковые (есть на ней переходник у меня включен vcc-gnd) — надо только подключать к хорошему источнику 5v, у меня от Lolin не заработало(хотя там есть один 5v), подключал сразу в зарядку — это разломанная ашановская USB зарядка за 120 рублей — справляется.

Если все посчитать по цене с платами то будет рублей 1500 — уже можно купить готовую Wi-Fi розетку у китайцев — её правда никак не запрограммировать под то что нужно! Сборка занимает много времени и пальцы почему то кровят при этом…

Вот код для LoLin

#include <PubSubClient.h>
#include <DHT_U.h>
#include <DHT.h>
#include <ESP8266WiFi.h>
#include <EEPROM.h>

// Uncomment one of the lines bellow for whatever DHT sensor type you're using!
//#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
#define LED_BUILTIN 2

// Change the credentials below, so your ESP8266 connects to your router
const char* ssid = "imyatochkidostupa";
const char* password = "parolottochki";
const char* mqttUser = "name";
const char* mqttPassword = "contasenya";

const char* mqttTopicHumidity = "room1/humidity";
const char* mqttTopicTemperature = "room1/temperature";
const char* mqttTopicWifi = "room1/wifistatus";
const char* mqttTopicPower = "room1/powerstatus";
// power 1 settings start
const char* mqttTopicButtonPower1 = "power/buttonunit1";
const char* mqttTopicButtonStatusPower1 = "power/buttonstatusunit1";
const char* mqttTopicPower1status = "power/unit1status";
int buttonpower1;
const char* mqttTopicButtonPower1auto = "power/buttonunit1auto";
const char* mqttTopicButtonStatusPower1auto = "power/buttonstatusunit1auto";
int buttonpower1auto;
const char* mqttTopicButtonPower1case = "power/buttonunit1case";
const char* mqttTopicButtonStatusPower1case = "power/buttonstatusunit1case";
int buttonpower1case;
const char* mqttTopicButtonPower1temp = "power/buttonunit1temp";
const char* mqttTopicButtonStatusPower1temp = "power/buttonstatusunit1temp";
int8_t buttonpower1temp;
const char* mqttTopicButtonPower1time = "power/buttonunit1time";
const char* mqttTopicButtonStatusPower1time = "power/buttonstatusunit1time";
unsigned long buttonpower1time;
unsigned long lastMeasure21 = 0;
unsigned long reruntime; 
// power 1 settings end

// power 2 settings start
const char* mqttTopicButtonPower2 = "power/buttonunit2";
const char* mqttTopicButtonStatusPower2 = "power/buttonstatusunit2";
const char* mqttTopicPower2status = "power/unit2status";
int buttonpower2;
const char* mqttTopicButtonPower2auto = "power/buttonunit2auto";
const char* mqttTopicButtonStatusPower2auto = "power/buttonstatusunit2auto";
int buttonpower2auto;
const char* mqttTopicButtonPower2case = "power/buttonunit2case";
const char* mqttTopicButtonStatusPower2case = "power/buttonstatusunit2case";
int buttonpower2case;
const char* mqttTopicButtonPower2temp = "power/buttonunit2temp";
const char* mqttTopicButtonStatusPower2temp = "power/buttonstatusunit2temp";
int8_t buttonpower2temp;
const char* mqttTopicButtonPower2time = "power/buttonunit2time";
const char* mqttTopicButtonStatusPower2time = "power/buttonstatusunit2time";
unsigned long buttonpower2time;
unsigned long lastMeasure22 = 0;
unsigned long reruntime2; 
// power 2 settings end


// Change the variable to your Raspberry Pi IP address, so it connects to your MQTT broker
const char* mqtt_server = "192.168.1.209";


const int DHTPin = 1;
const int power1 = 4;
const int power2 = 5;
int tempwarning = 3;
boolean wifistatus = false;
boolean powerstatus = false;


// Timers auxiliar variables
unsigned long now = millis();
unsigned long lastMeasure = 0;

const char* mqttTopicResendTime = "room1/resendtime";
const char* mqttTopicResendTimeStatus = "room1/resendtimestatus";
unsigned long resendtime = 30000; 
long resendtimetemp; 

//eeprom memory use
//power1 settings
// 1,2,3,4,5-8,
//power2 settings
// 9,10,11,12,13-16,
//data resend time
// 17-20

// Initializes the espClient.
WiFiClient espClient;
PubSubClient client(espClient);

// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);


void setup() {
  EEPROM.begin(32);
  dht.begin();
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  pinMode(power2, OUTPUT); 
  pinMode(power1, OUTPUT);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  // power 1 settings start
 buttonpower1 = EEPROM.read(1);
 buttonpower1auto = EEPROM.read(2);
 buttonpower1case = EEPROM.read(3);
 buttonpower1temp = (int8_t)EEPROM.read(4);
 buttonpower1time = EEPROMReadlong(5);
 reruntime = 60000 * buttonpower1time;
 // power 1 settings end

   // power 2 settings start
 buttonpower2 = EEPROM.read(9);
 buttonpower2auto = EEPROM.read(10);
 buttonpower2case = EEPROM.read(11);
 buttonpower2temp = (int8_t)EEPROM.read(12);
 buttonpower2time = EEPROMReadlong(13);
 reruntime2 = 60000 * buttonpower2time;
 // power 2 settings end

 resendtimetemp = EEPROMReadlong(17);
 resendtime = 1000 * resendtimetemp + 500;
 
digitalWrite(power2, HIGH);
digitalWrite(power1, HIGH);
  client.setCallback(callback);
  //Serial.begin(9600);
}


//This function will write a 4 byte (32bit) long to the eeprom at
//the specified address to address + 3.
void EEPROMWritelong(int address, long value)
      {
      //Decomposition from a long to 4 bytes by using bitshift.
      //One = Most significant -> Four = Least significant byte
      byte four = (value & 0xFF);
      byte three = ((value >> 8) & 0xFF);
      byte two = ((value >> 16) & 0xFF);
      byte one = ((value >> 24) & 0xFF);

      //Write the 4 bytes into the eeprom memory.
      EEPROM.write(address, four);
      EEPROM.commit();
      EEPROM.write(address + 1, three);
      EEPROM.commit();
      EEPROM.write(address + 2, two);
      EEPROM.commit();
      EEPROM.write(address + 3, one);
      EEPROM.commit();
      }

long EEPROMReadlong(long address)
      {
      //Read the 4 bytes from the eeprom memory.
      long four = EEPROM.read(address);
      long three = EEPROM.read(address + 1);
      long two = EEPROM.read(address + 2);
      long one = EEPROM.read(address + 3);

      //Return the recomposed long by using bitshift.
      return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
      }
      
// Don't change the function below. This functions connects your ESP8266 to your router
void setup_wifi() {
  delay(10);
  // We start by connecting to a WiFi network
  WiFi.begin(ssid, password);

}

// This functions is executed when some device publishes a message to a topic that your ESP8266 is subscribed to
// Change the function below to add logic to your program, so when a device publishes a message to a topic that 
// your ESP8266 is subscribed you can actually do something
void callback(String topic, byte* message, unsigned int length) {
  String messageTemp; 
  for (int i = 0; i < length; i++) {
   messageTemp += (char)message[i];
  };
  
// power 1 settings start 
  if(topic==mqttTopicButtonPower1){
     if(messageTemp == "do"){       
if (buttonpower1 == 1)
{
client.publish(mqttTopicButtonStatusPower1, "off");
client.publish(mqttTopicPower1status, "0");
buttonpower1 = 0;
EEPROM.write(1, buttonpower1);
EEPROM.commit();
digitalWrite(power1, HIGH);
}else {
client.publish(mqttTopicButtonStatusPower1, "on");
client.publish(mqttTopicPower1status, "1");
buttonpower1 = 1;
EEPROM.write(1, buttonpower1);
EEPROM.commit();
digitalWrite(power1, LOW);
};
delay(500);
 };
 };  
 if(topic==mqttTopicButtonPower1auto){
     if(messageTemp == "do"){       
if (buttonpower1auto == 1)
{
client.publish(mqttTopicButtonStatusPower1auto, "off");

buttonpower1auto = 0;
EEPROM.write(2, buttonpower1auto);
EEPROM.commit();

}else {
client.publish(mqttTopicButtonStatusPower1auto, "on");

buttonpower1auto = 1;
EEPROM.write(2, buttonpower1auto);
EEPROM.commit();
};
delay(500);
 };
 };

 if(topic==mqttTopicButtonPower1case){
     if(messageTemp == "do"){       
if (buttonpower1case == 1)
{
client.publish(mqttTopicButtonStatusPower1case, "less");
buttonpower1case = 0;
EEPROM.write(3, buttonpower1case);
EEPROM.commit();

}else {
client.publish(mqttTopicButtonStatusPower1case, "more");
buttonpower1case = 1;
EEPROM.write(3, buttonpower1case);
EEPROM.commit();
};
delay(500);
 };
 };
 if(topic==mqttTopicButtonPower1temp){
buttonpower1temp = messageTemp.toInt();
static char TempTemp[7];
    dtostrf(buttonpower1temp, 6, 0, TempTemp);
client.publish(mqttTopicButtonStatusPower1temp, TempTemp);
EEPROM.write(4, buttonpower1temp);
EEPROM.commit();
delay(500);
 };
 if(topic==mqttTopicButtonPower1time){
buttonpower1time = messageTemp.toInt();
static char TimeTemp[7];
    dtostrf(buttonpower1time, 6, 0, TimeTemp);
client.publish(mqttTopicButtonStatusPower1time, TimeTemp);
//EEPROM.write(5, buttonpower1time);
EEPROMWritelong(5, buttonpower1time);
reruntime = 60000 * buttonpower1time;
delay(500);
 };


// power 1 settings end

  if(topic==mqttTopicResendTime){
resendtimetemp = messageTemp.toInt();
static char TimeResend[7];
    dtostrf(resendtimetemp, 6, 0, TimeResend);
client.publish(mqttTopicResendTimeStatus, TimeResend);
EEPROMWritelong(17, resendtimetemp);
resendtime = 1000 * resendtimetemp; 
delay(500);
 };
 
// power 2 settings start 
  if(topic==mqttTopicButtonPower2){
     if(messageTemp == "do"){       
if (buttonpower2 == 1)
{
client.publish(mqttTopicButtonStatusPower2, "off");
client.publish(mqttTopicPower2status, "0");
buttonpower2 = 0;
EEPROM.write(9, buttonpower2);
EEPROM.commit();
digitalWrite(power2, HIGH);
}else {
client.publish(mqttTopicButtonStatusPower2, "on");
client.publish(mqttTopicPower2status, "1");
buttonpower2 = 1;
EEPROM.write(9, buttonpower2);
EEPROM.commit();
digitalWrite(power2, LOW);
};
delay(500);
 };
 };  
 if(topic==mqttTopicButtonPower2auto){
     if(messageTemp == "do"){       
if (buttonpower2auto == 1)
{
client.publish(mqttTopicButtonStatusPower2auto, "off");

buttonpower2auto = 0;
EEPROM.write(10, buttonpower2auto);
EEPROM.commit();

}else {
client.publish(mqttTopicButtonStatusPower2auto, "on");

buttonpower2auto = 1;
EEPROM.write(10, buttonpower2auto);
EEPROM.commit();
};
delay(500);
 };
 };

 if(topic==mqttTopicButtonPower2case){
     if(messageTemp == "do"){       
if (buttonpower2case == 1)
{
client.publish(mqttTopicButtonStatusPower2case, "less");
buttonpower2case = 0;
EEPROM.write(11, buttonpower2case);
EEPROM.commit();

}else {
client.publish(mqttTopicButtonStatusPower2case, "more");
buttonpower2case = 1;
EEPROM.write(11, buttonpower2case);
EEPROM.commit();
};
delay(500);
 };
 };
 if(topic==mqttTopicButtonPower2temp){
buttonpower2temp = messageTemp.toInt();
static char TempTemp[7];
    dtostrf(buttonpower2temp, 6, 0, TempTemp);
client.publish(mqttTopicButtonStatusPower2temp, TempTemp);
EEPROM.write(12, buttonpower2temp);
EEPROM.commit();
delay(500);
 };
 if(topic==mqttTopicButtonPower2time){
buttonpower2time = messageTemp.toInt();
static char TimeTemp[7];
    dtostrf(buttonpower2time, 6, 0, TimeTemp);
client.publish(mqttTopicButtonStatusPower2time, TimeTemp);
//EEPROM.write(5, buttonpower1time);
EEPROMWritelong(13, buttonpower2time);
reruntime2 = 60000 * buttonpower2time;
delay(500);
 };
// power 1 settings end
      
}

// This functions reconnects your ESP8266 to your MQTT broker
// Change the function below if you want to subscribe to more topics with your ESP8266 
void reconnect() {

    if (client.connect(WiFi.hostname().c_str(), mqttUser, mqttPassword)) {
      // Subscribe or resubscribe to a topic
      // You can subscribe to more topics (to control more LEDs in this example)
   
   // power 1 settings start
   client.subscribe(mqttTopicButtonPower1);
   client.subscribe(mqttTopicButtonPower1auto);
   client.subscribe(mqttTopicButtonPower1case);
   client.subscribe(mqttTopicButtonPower1temp);
   client.subscribe(mqttTopicButtonPower1time);
   // power 1 settings end

   // power 2 settings start
   client.subscribe(mqttTopicButtonPower2);
   client.subscribe(mqttTopicButtonPower2auto);
   client.subscribe(mqttTopicButtonPower2case);
   client.subscribe(mqttTopicButtonPower2temp);
   client.subscribe(mqttTopicButtonPower2time);
   // power 2 settings end
   client.subscribe(mqttTopicResendTime);
    } else {
      // Wait 5 seconds before retrying
      delay(500);
    }

}


void loop() {

  now = millis();

  //dont know what this string does, but without it all does not work
 if(!client.loop()) 
     client.connect("blabla");

  if (!client.connected()) {
   digitalWrite(LED_BUILTIN, LOW); 
    reconnect(); 
   digitalWrite(LED_BUILTIN, HIGH);   
     };


if (now - lastMeasure21 > reruntime) {
    lastMeasure21 = now;  
if (buttonpower1auto == 1) 
{ client.publish(mqttTopicPower1status, "0");
  client.publish(mqttTopicButtonStatusPower1, "off");
  digitalWrite(power1, HIGH);
  buttonpower1 = 0;
};

}; 

 if (now - lastMeasure22 > reruntime2) {
    lastMeasure22 = now;  
if (buttonpower2auto == 1) 
{ client.publish(mqttTopicPower2status, "0");
  client.publish(mqttTopicButtonStatusPower2, "off");
  digitalWrite(power2, HIGH);
  buttonpower2 = 0;
};

};        
    
if (now - lastMeasure > resendtime) {
    lastMeasure = now;  

    float hf = dht.readHumidity();
    static char humidityTemp[7];
    dtostrf(hf, 6, 1, humidityTemp);
    int8_t h = (int) hf;
    float tf = dht.readTemperature();
    static char temperatureTemp[7];
    dtostrf(tf, 6, 1, temperatureTemp);
    int8_t t = (int) tf;
    
    
// power 1 settings start
if (buttonpower1auto == 1) 
{ 

  
if (buttonpower1case == 1 )
{
if ( t >= buttonpower1temp)
{ 
 
  
  client.publish(mqttTopicPower1status, "1");
  client.publish(mqttTopicButtonStatusPower1, "on");
  digitalWrite(power1, LOW);
  buttonpower1 = 1;
  lastMeasure21 = now; 
};
};
if (buttonpower1case == 0 ) {
  if ( t <= buttonpower1temp)
{ 
  client.publish(mqttTopicPower1status, "1");
  client.publish(mqttTopicButtonStatusPower1, "on");
 digitalWrite(power1, LOW);
 buttonpower1 = 1;
  lastMeasure21 = now;
};
};
};
// power 1  settings end


// power 2 settings start
if (buttonpower2auto == 1) 
{
if (buttonpower2case == 1 )
{
if ( h >= buttonpower2temp)
{ client.publish(mqttTopicPower2status, "1");
  client.publish(mqttTopicButtonStatusPower2, "on");
  digitalWrite(power2, LOW);
  buttonpower2 = 1;
  lastMeasure22 = now; 
};
};
if (buttonpower2case == 0 ) {
  if ( h <= buttonpower2temp)
{ 
  client.publish(mqttTopicPower2status, "1");
  client.publish(mqttTopicButtonStatusPower2, "on");
 digitalWrite(power2, LOW);
 buttonpower2 = 1;
  lastMeasure22 = now;
};
};
};
// power 2 settings end

if (client.connected()) {


    // Publishes 
digitalWrite(LED_BUILTIN, LOW);   digitalWrite(LED_BUILTIN, LOW);

    
    client.publish(mqttTopicTemperature, temperatureTemp);
    client.publish(mqttTopicHumidity, humidityTemp);

    static char TimeResend[7];
    dtostrf(resendtimetemp, 6, 0, TimeResend);
client.publish(mqttTopicResendTimeStatus, TimeResend);

    // power 1 settings start
    static char TempTemp[7];
    dtostrf(buttonpower1temp, 6, 0, TempTemp);
client.publish(mqttTopicButtonStatusPower1temp, TempTemp);
static char TimeTemp[7];
    dtostrf(buttonpower1time, 6, 0, TimeTemp);
client.publish(mqttTopicButtonStatusPower1time, TimeTemp);
  if (digitalRead(power1) == LOW)
 {
  if (buttonpower1 == 1)
{
  client.publish(mqttTopicPower1status, "1");
  client.publish(mqttTopicButtonStatusPower1, "on");
} else {
  client.publish(mqttTopicPower1status, "0");
  client.publish(mqttTopicButtonStatusPower1, "off");
  digitalWrite(power1, HIGH);
  buttonpower1 = 0;
};
 } else {
  if (buttonpower1 == 0)
{
  client.publish(mqttTopicPower1status, "0");
  client.publish(mqttTopicButtonStatusPower1, "off");
} else {
  client.publish(mqttTopicPower1status, "1");
  client.publish(mqttTopicButtonStatusPower1, "on");
  digitalWrite(power1, LOW);
  buttonpower1 = 1;
};

 };
 if (buttonpower1auto == 1)
{
  client.publish(mqttTopicButtonStatusPower1auto, "on");
} else {
  client.publish(mqttTopicButtonStatusPower1auto, "off");

}; 
 if (buttonpower1case == 1)
{
  client.publish(mqttTopicButtonStatusPower1case, "more");
} else {
  client.publish(mqttTopicButtonStatusPower1case, "less");

}; 
// power 1 settings end


 // power 2 settings start
    static char TempTemp2[7];
    dtostrf(buttonpower2temp, 6, 0, TempTemp2);
    client.publish(mqttTopicButtonStatusPower2temp, TempTemp2);
    static char TimeTemp2[7];
    dtostrf(buttonpower2time, 6, 0, TimeTemp2);
    client.publish(mqttTopicButtonStatusPower2time, TimeTemp2);
    
  if (digitalRead(power2) == LOW)
 {
  if (buttonpower2 == 1)
{
  client.publish(mqttTopicPower2status, "1");
  client.publish(mqttTopicButtonStatusPower2, "on");
} else {
  client.publish(mqttTopicPower2status, "0");
  client.publish(mqttTopicButtonStatusPower2, "off");
  digitalWrite(power2, HIGH);
  buttonpower2 = 0;
};
 } else {
  if (buttonpower2 == 0)
{
  client.publish(mqttTopicPower2status, "0");
  client.publish(mqttTopicButtonStatusPower2, "off");
} else {
  client.publish(mqttTopicPower2status, "1");
  client.publish(mqttTopicButtonStatusPower2, "on");
  digitalWrite(power2, LOW);
  buttonpower2 = 1;
};

 };
 if (buttonpower2auto == 1)
{
  client.publish(mqttTopicButtonStatusPower2auto, "on");
} else {
  client.publish(mqttTopicButtonStatusPower2auto, "off");

}; 
 if (buttonpower2case == 1)
{
  client.publish(mqttTopicButtonStatusPower2case, "more");
} else {
  client.publish(mqttTopicButtonStatusPower2case, "less");

}; 
// power 2 settings end

 if (!wifistatus)
 {
client.publish(mqttTopicWifi, "0");
wifistatus = true;
  
 } else {
 client.publish(mqttTopicWifi, "1"); 
 };
if (!powerstatus)
        {
            client.publish(mqttTopicPower, "0");
            powerstatus = true;
        } else {
            client.publish(mqttTopicPower, "1"); 
     };

  digitalWrite(LED_BUILTIN, HIGH);
  };
 
};

}

ВАЖНО: При первом запуске после прошивки esp8266 надо задать в во вкладке Settings в Node-Red UI интервал обновления в квадрате Storage Room Send/Check interval Settings, иначе там может быть любая фигня, читает из пустого места в памяти, а он может быть не пустым после прошивки. Тоже справедливо для других настроек, но не так критично

По отсылке данных он делает тоже что и погодный модуль, только нет дачика воздуха. Так же есть настройка интервала в во вкладке Settings в Node-Red UI, но там еще появляют настройки включения розеток при заданном условии, они срабатываю даже если нет подключения к Node-Red.

Вот кирпичи отвечающие за модель умной розетки в Node-Red

И текстом, который можно себе импортировать

[{"id":"5fb16ee4.f988e","type":"ui_chart","z":"e60c0f81.64c18","name":"Temperature","group":"91158576.4f6178","order":2,"width":0,"height":0,"label":"Temperature graph","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#8e0911","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#910304","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":610,"y":1040,"wires":[[],[]]},{"id":"f8830669.9e10c8","type":"mqtt in","z":"e60c0f81.64c18","name":"Temperature","topic":"room1/temperature","qos":"2","broker":"572eed08.5bb714","x":410,"y":920,"wires":[["5fb16ee4.f988e","b77ce775.ac0f98","8a1fb374.d6b14","692ab0d4.84698"]]},{"id":"7c990247.71a3cc","type":"file","z":"e60c0f81.64c18","name":"Write temp_room1.log","filename":"/root/iot_data/temp_room1.log","appendNewline":true,"createDir":false,"overwriteFile":"false","x":840,"y":920,"wires":[[]]},{"id":"b77ce775.ac0f98","type":"function","z":"e60c0f81.64c18","name":"Add time to data","func":"var timenow=flow.get('time');\nmsg.payload = timenow + ' '+ msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":920,"wires":[["7c990247.71a3cc"]]},{"id":"4293b7d1.57e368","type":"ui_chart","z":"e60c0f81.64c18","name":"Humidity","group":"91158576.4f6178","order":4,"width":0,"height":0,"label":"Humidity graph","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#0971c1","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":600,"y":1220,"wires":[[],[]]},{"id":"c5e2d074.7634","type":"mqtt in","z":"e60c0f81.64c18","name":"Humidity","topic":"room1/humidity","qos":"2","broker":"572eed08.5bb714","x":400,"y":1100,"wires":[["4293b7d1.57e368","6d8e3a37.c02eb4","7d33c3bc.f07a7c","c49d559f.8ef4c8"]]},{"id":"6d7903e5.1fdeac","type":"file","z":"e60c0f81.64c18","name":"Write humi_room1.log","filename":"/root/iot_data/humi_room1.log","appendNewline":true,"createDir":false,"overwriteFile":"false","x":840,"y":1100,"wires":[[]]},{"id":"6d8e3a37.c02eb4","type":"function","z":"e60c0f81.64c18","name":"Add time to data","func":"var timenow=flow.get('time');\nmsg.payload = timenow + ' '+ msg.payload;\nreturn msg;","outputs":1,"noerr":0,"x":620,"y":1100,"wires":[["6d7903e5.1fdeac"]]},{"id":"75b1ee83.fb8dc","type":"ui_chart","z":"e60c0f81.64c18","name":"Power 1","group":"fba9a7a9.8c5418","order":3,"width":0,"height":0,"label":"Power 1 use","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"1","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":true,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#680808","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":680,"y":140,"wires":[[],[]]},{"id":"6bb7ff0c.048ea","type":"mqtt in","z":"e60c0f81.64c18","name":"","topic":"power/unit1status","qos":"2","broker":"572eed08.5bb714","x":420,"y":140,"wires":[["75b1ee83.fb8dc"]]},{"id":"f7a70f9f.25cec","type":"mqtt in","z":"e60c0f81.64c18","name":"MQQT status","topic":"room1/wifistatus","qos":"2","broker":"572eed08.5bb714","x":410,"y":800,"wires":[["e586b3bf.742ce"]]},{"id":"e586b3bf.742ce","type":"ui_chart","z":"e60c0f81.64c18","name":"MQQT status","group":"c8aa5b51.ed6ff8","order":1,"width":0,"height":0,"label":"MQQT was lost at","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"1","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":true,"colors":["#000000","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#77090a","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":570,"y":800,"wires":[[],[]]},{"id":"83fc107.a5b6ef","type":"ui_button","z":"e60c0f81.64c18","name":"","group":"fba9a7a9.8c5418","order":2,"width":0,"height":0,"passthru":false,"label":"press to change","color":"","bgcolor":"","icon":"","payload":"do","payloadType":"str","topic":"power/buttonunit1","x":420,"y":20,"wires":[["1d72bb8f.7aa464"]]},{"id":"1d72bb8f.7aa464","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit1","qos":"","retain":"","broker":"572eed08.5bb714","x":650,"y":20,"wires":[]},{"id":"c1ce83be.d59b6","type":"mqtt in","z":"e60c0f81.64c18","name":"Power1 Button status","topic":"power/buttonstatusunit1","qos":"2","broker":"572eed08.5bb714","x":440,"y":80,"wires":[["44e98139.d58"]]},{"id":"44e98139.d58","type":"ui_text","z":"e60c0f81.64c18","group":"fba9a7a9.8c5418","order":1,"width":0,"height":0,"name":"","label":"Power 1 (override by auto control):","format":"{{msg.payload}}","layout":"row-spread","x":720,"y":80,"wires":[]},{"id":"e8a32ad3.656188","type":"ui_button","z":"e60c0f81.64c18","name":"","group":"fba9a7a9.8c5418","order":5,"width":0,"height":0,"passthru":false,"label":"press to change","color":"","bgcolor":"","icon":"","payload":"do","payloadType":"str","topic":"power/buttonunit1auto","x":420,"y":200,"wires":[["a947e584.e98788"]]},{"id":"a947e584.e98788","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit1auto","qos":"","retain":"","broker":"572eed08.5bb714","x":660,"y":200,"wires":[]},{"id":"d30d9525.ffe7b8","type":"mqtt in","z":"e60c0f81.64c18","name":"power1 Auto  Button status","topic":"power/buttonstatusunit1auto","qos":"2","broker":"572eed08.5bb714","x":450,"y":260,"wires":[["6c440e2c.b0432"]]},{"id":"6c440e2c.b0432","type":"ui_text","z":"e60c0f81.64c18","group":"fba9a7a9.8c5418","order":4,"width":0,"height":0,"name":"","label":"Power 1 Temprutare Auto Control:","format":"{{msg.payload}}","layout":"row-spread","x":720,"y":260,"wires":[]},{"id":"7dad518e.e0f73","type":"ui_button","z":"e60c0f81.64c18","name":"","group":"fba9a7a9.8c5418","order":7,"width":0,"height":0,"passthru":false,"label":"press to change","color":"","bgcolor":"","icon":"","payload":"do","payloadType":"str","topic":"power/buttonunit1case","x":420,"y":320,"wires":[["f83f2f6b.a2178"]]},{"id":"f83f2f6b.a2178","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit1case","qos":"","retain":"","broker":"572eed08.5bb714","x":660,"y":320,"wires":[]},{"id":"aefd6457.2fb318","type":"mqtt in","z":"e60c0f81.64c18","name":"power1 Auto  Button Case","topic":"power/buttonstatusunit1case","qos":"2","broker":"572eed08.5bb714","x":450,"y":380,"wires":[["5f62a213.e2221c"]]},{"id":"5f62a213.e2221c","type":"ui_text","z":"e60c0f81.64c18","group":"fba9a7a9.8c5418","order":6,"width":0,"height":0,"name":"","label":"When the temperature is...:","format":"{{msg.payload}}","layout":"col-center","x":740,"y":380,"wires":[]},{"id":"2023e629.f7fcda","type":"ui_slider","z":"e60c0f81.64c18","name":"","label":"slider","group":"fba9a7a9.8c5418","order":9,"width":0,"height":0,"passthru":true,"outs":"end","topic":"power/buttonunit1temp","min":"-35","max":"65","step":1,"x":390,"y":440,"wires":[["81263bde.91ff88"]]},{"id":"81263bde.91ff88","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit1temp","qos":"","retain":"","broker":"572eed08.5bb714","x":600,"y":440,"wires":[]},{"id":"ea28795a.ea98c8","type":"mqtt in","z":"e60c0f81.64c18","name":"power1 Auto  Button Temp","topic":"power/buttonstatusunit1temp","qos":"2","broker":"572eed08.5bb714","x":450,"y":500,"wires":[["cda707f3.409308"]]},{"id":"cda707f3.409308","type":"ui_text","z":"e60c0f81.64c18","group":"fba9a7a9.8c5418","order":8,"width":0,"height":0,"name":"","label":"than...:","format":"{{msg.payload}}","layout":"col-center","x":670,"y":500,"wires":[]},{"id":"518c1721.0ef2f8","type":"ui_slider","z":"e60c0f81.64c18","name":"","label":"slider","group":"fba9a7a9.8c5418","order":12,"width":0,"height":0,"passthru":true,"outs":"end","topic":"power/buttonunit1time","min":"1","max":"1000","step":"5","x":390,"y":560,"wires":[["769e0778.e2f7a8"]]},{"id":"769e0778.e2f7a8","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit1time","qos":"","retain":"","broker":"572eed08.5bb714","x":600,"y":560,"wires":[]},{"id":"8e77c553.3d1568","type":"mqtt in","z":"e60c0f81.64c18","name":"power1 Auto  Button Time","topic":"power/buttonstatusunit1time","qos":"2","broker":"572eed08.5bb714","x":450,"y":620,"wires":[["b368c669.6da6d8"]]},{"id":"b368c669.6da6d8","type":"ui_text","z":"e60c0f81.64c18","group":"fba9a7a9.8c5418","order":11,"width":0,"height":0,"name":"","label":"turn on power for (min)...:","format":"{{msg.payload}}","layout":"col-center","x":730,"y":620,"wires":[]},{"id":"81acd203.1a222","type":"mqtt in","z":"e60c0f81.64c18","name":"Power status","topic":"room1/powerstatus","qos":"2","broker":"572eed08.5bb714","x":410,"y":860,"wires":[["ab1a1085.b7e91"]]},{"id":"ab1a1085.b7e91","type":"ui_chart","z":"e60c0f81.64c18","name":"Power status","group":"c8aa5b51.ed6ff8","order":2,"width":0,"height":0,"label":"Power was lost at","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"1","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":true,"colors":["#000000","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#77090a","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":570,"y":860,"wires":[[],[]]},{"id":"311965fc.bcde5a","type":"ui_chart","z":"e60c0f81.64c18","name":"Power 2","group":"5d3c2f30.e95b4","order":3,"width":0,"height":0,"label":"Power 2 use","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"1","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":true,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#680808","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":1260,"y":140,"wires":[[],[]]},{"id":"b9e207d5.faf328","type":"mqtt in","z":"e60c0f81.64c18","name":"","topic":"power/unit2status","qos":"2","broker":"572eed08.5bb714","x":1000,"y":140,"wires":[["311965fc.bcde5a"]]},{"id":"c0f3e890.50a9e8","type":"ui_button","z":"e60c0f81.64c18","name":"","group":"5d3c2f30.e95b4","order":2,"width":0,"height":0,"passthru":false,"label":"press to change","color":"","bgcolor":"","icon":"","payload":"do","payloadType":"str","topic":"power/buttonunit2","x":1000,"y":20,"wires":[["9947f5c1.130478"]]},{"id":"9947f5c1.130478","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit2","qos":"","retain":"","broker":"572eed08.5bb714","x":1230,"y":20,"wires":[]},{"id":"25644cfa.7b9654","type":"mqtt in","z":"e60c0f81.64c18","name":"Power2 Button status","topic":"power/buttonstatusunit2","qos":"2","broker":"572eed08.5bb714","x":1020,"y":80,"wires":[["63e87dc0.334cb4"]]},{"id":"63e87dc0.334cb4","type":"ui_text","z":"e60c0f81.64c18","group":"5d3c2f30.e95b4","order":1,"width":0,"height":0,"name":"","label":"Power 2 (override by auto control):","format":"{{msg.payload}}","layout":"row-spread","x":1300,"y":80,"wires":[]},{"id":"6c3e3c55.f81e54","type":"ui_button","z":"e60c0f81.64c18","name":"","group":"5d3c2f30.e95b4","order":5,"width":0,"height":0,"passthru":false,"label":"press to change","color":"","bgcolor":"","icon":"","payload":"do","payloadType":"str","topic":"power/buttonunit2auto","x":1000,"y":200,"wires":[["f5da73f4.22916"]]},{"id":"f5da73f4.22916","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit2auto","qos":"","retain":"","broker":"572eed08.5bb714","x":1240,"y":200,"wires":[]},{"id":"1700d32.26aca2d","type":"mqtt in","z":"e60c0f81.64c18","name":"power2 Auto  Button status","topic":"power/buttonstatusunit2auto","qos":"2","broker":"572eed08.5bb714","x":1030,"y":260,"wires":[["baba5a9c.6601b8"]]},{"id":"baba5a9c.6601b8","type":"ui_text","z":"e60c0f81.64c18","group":"5d3c2f30.e95b4","order":4,"width":0,"height":0,"name":"","label":"Power 2 Humidity Auto Control:","format":"{{msg.payload}}","layout":"row-spread","x":1290,"y":260,"wires":[]},{"id":"dc8fc8ce.aef588","type":"ui_button","z":"e60c0f81.64c18","name":"","group":"5d3c2f30.e95b4","order":7,"width":0,"height":0,"passthru":false,"label":"press to change","color":"","bgcolor":"","icon":"","payload":"do","payloadType":"str","topic":"power/buttonunit2case","x":1000,"y":320,"wires":[["ec4c9b15.062838"]]},{"id":"ec4c9b15.062838","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit2case","qos":"","retain":"","broker":"572eed08.5bb714","x":1240,"y":320,"wires":[]},{"id":"39c84012.dc4ee","type":"mqtt in","z":"e60c0f81.64c18","name":"power2 Auto  Button Case","topic":"power/buttonstatusunit2case","qos":"2","broker":"572eed08.5bb714","x":1030,"y":380,"wires":[["94a9fa82.c5ec98"]]},{"id":"94a9fa82.c5ec98","type":"ui_text","z":"e60c0f81.64c18","group":"5d3c2f30.e95b4","order":6,"width":0,"height":0,"name":"","label":"When the humidity is...:","format":"{{msg.payload}}","layout":"col-center","x":1310,"y":380,"wires":[]},{"id":"d8b512eb.d148c","type":"ui_slider","z":"e60c0f81.64c18","name":"","label":"slider","group":"5d3c2f30.e95b4","order":9,"width":0,"height":0,"passthru":true,"outs":"end","topic":"power/buttonunit2temp","min":"0","max":"100","step":1,"x":970,"y":440,"wires":[["ae0c8dc4.727a9"]]},{"id":"ae0c8dc4.727a9","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit2temp","qos":"","retain":"","broker":"572eed08.5bb714","x":1180,"y":440,"wires":[]},{"id":"20495eae.c1ac82","type":"mqtt in","z":"e60c0f81.64c18","name":"power2 Auto  Button Hum","topic":"power/buttonstatusunit2temp","qos":"2","broker":"572eed08.5bb714","x":1030,"y":500,"wires":[["96679630.ad9d48"]]},{"id":"96679630.ad9d48","type":"ui_text","z":"e60c0f81.64c18","group":"5d3c2f30.e95b4","order":8,"width":0,"height":0,"name":"","label":"than...:","format":"{{msg.payload}}","layout":"col-center","x":1250,"y":500,"wires":[]},{"id":"af1a3232.ba29","type":"ui_slider","z":"e60c0f81.64c18","name":"","label":"slider","group":"5d3c2f30.e95b4","order":12,"width":0,"height":0,"passthru":true,"outs":"end","topic":"power/buttonunit2time","min":"1","max":"1000","step":"5","x":970,"y":560,"wires":[["401038f3.9af088"]]},{"id":"401038f3.9af088","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"power/buttonunit2time","qos":"","retain":"","broker":"572eed08.5bb714","x":1180,"y":560,"wires":[]},{"id":"87874ed1.92dfb","type":"mqtt in","z":"e60c0f81.64c18","name":"power1 Auto  Button Time","topic":"power/buttonstatusunit2time","qos":"2","broker":"572eed08.5bb714","x":1030,"y":620,"wires":[["ba6bd99.57a9e28"]]},{"id":"ba6bd99.57a9e28","type":"ui_text","z":"e60c0f81.64c18","group":"5d3c2f30.e95b4","order":11,"width":0,"height":0,"name":"","label":"turn on power for (min)...:","format":"{{msg.payload}}","layout":"col-center","x":1310,"y":620,"wires":[]},{"id":"4bea9f97.478f6","type":"ui_slider","z":"e60c0f81.64c18","name":"","label":"slider","group":"5b5e436d.06525c","order":2,"width":0,"height":0,"passthru":true,"outs":"end","topic":"room1/resendtime","min":"15","max":"600","step":"5","x":390,"y":680,"wires":[["c9cf61b2.27fc8"]]},{"id":"c9cf61b2.27fc8","type":"mqtt out","z":"e60c0f81.64c18","name":"","topic":"room1/resendtime","qos":"","retain":"","broker":"572eed08.5bb714","x":590,"y":680,"wires":[]},{"id":"98b50a35.88b558","type":"mqtt in","z":"e60c0f81.64c18","name":"resend time","topic":"room1/resendtimestatus","qos":"2","broker":"572eed08.5bb714","x":410,"y":740,"wires":[["e763f56c.4c08e8"]]},{"id":"e763f56c.4c08e8","type":"ui_text","z":"e60c0f81.64c18","group":"5b5e436d.06525c","order":1,"width":0,"height":0,"name":"","label":"Storage Room sensors - send and check  data  every (seconds):","format":"{{msg.payload}}","layout":"col-center","x":770,"y":740,"wires":[]},{"id":"8a1fb374.d6b14","type":"ui_text","z":"e60c0f81.64c18","group":"91158576.4f6178","order":1,"width":0,"height":0,"name":"","label":"Temperature now is","format":"{{msg.payload}}","layout":"row-center","x":630,"y":1000,"wires":[]},{"id":"7d33c3bc.f07a7c","type":"ui_text","z":"e60c0f81.64c18","group":"91158576.4f6178","order":3,"width":0,"height":0,"name":"","label":"Humidity now is","format":"{{msg.payload}}","layout":"row-center","x":620,"y":1140,"wires":[]},{"id":"692ab0d4.84698","type":"ui_text","z":"e60c0f81.64c18","group":"fba9a7a9.8c5418","order":10,"width":0,"height":0,"name":"","label":"(Temperature now is","format":"{{msg.payload}})","layout":"row-left","x":640,"y":960,"wires":[]},{"id":"c49d559f.8ef4c8","type":"ui_text","z":"e60c0f81.64c18","group":"5d3c2f30.e95b4","order":10,"width":0,"height":0,"name":"","label":"(Humidity now is","format":"{{msg.payload}})","layout":"row-left","x":620,"y":1180,"wires":[]},{"id":"91158576.4f6178","type":"ui_group","z":"","name":"Storage Room Data","tab":"274c10df.50bbd","order":1,"disp":true,"width":"10","collapse":false},{"id":"572eed08.5bb714","type":"mqtt-broker","z":"","name":"Mosquitto Orange","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"fba9a7a9.8c5418","type":"ui_group","z":"","name":"Storage Room Power 1 Settings","tab":"5d7f916a.3be03","order":3,"disp":true,"width":"6","collapse":false},{"id":"c8aa5b51.ed6ff8","type":"ui_group","z":"","name":"Storage Room Status","tab":"274c10df.50bbd","order":2,"disp":true,"width":"10","collapse":false},{"id":"5d3c2f30.e95b4","type":"ui_group","z":"","name":"Storage Room Power 2 Settings","tab":"5d7f916a.3be03","order":3,"disp":true,"width":"6","collapse":false},{"id":"5b5e436d.06525c","type":"ui_group","z":"","name":"Storage Room Send/Check interval Settings","tab":"5d7f916a.3be03","order":4,"disp":true,"width":"6","collapse":false},{"id":"274c10df.50bbd","type":"ui_tab","z":"","name":"Storage Room","icon":"dashboard","order":1},{"id":"5d7f916a.3be03","type":"ui_tab","z":"","name":"Settings","icon":"dashboard","order":4}]

Скриншот с данными даже не буду показывать, это не интересно совсем. Вот сриншот с настройками.

Настройки для каждой розетки столбцом. Первая реагирует на температуру, вторая на влажность. Можно в настройках включить или выключать немедленно розетку — это изменится если включена автоматика. Виден график включения розетки за 24 часа, 1 значит включено, значения отображается мгновенно. Есть настройки включить автоматики, выбрать если больше или меньше, заданного значения(тут же показывается какое сейчас значение) то включить розетку(иначе выключить), на заданный интервал.

Проверил работает, но баги конечно могут оставаться. Оказалось много особенностей, так например в память нельзя писать булевые значения, поменял их на 0 и 1, хотя это оно и есть. Для оценки температуры переводил цифры с запятой от датчиков в целые, так как(как многие кстати замечают) сравнение на больше меньше цифр с запятой непредсказуемо — так оно и есть. Много, много часов занимательного багхантинга все это мне принесло эххх.

ОСТОРОЖНО: Остается непонятый баг, иногда(1-2 раза в 1-2 дня) автоматика(если включена) включает розетку, хотя показаний к тому нет, после отключает само по таймауту. Значения температуры пишу в файл и они норм, но все равно срабатывает, не могу понять почему

Просто собираем температуру процессоров со всех компьютеров
Ну как со всех… с Windows наверное тоже, как-то, наверное… ну не приспособлены онo для IoT, даже через Bash For Windows простой запуск по расписанию смогли запороть!

Есть компьютеры которые реально работают 24 часа, есть которые включаются на пару часов. На них ставим MQQT client и посылаем данные температуры.

Но начну с Node-Red вот кирпичи которые за это отвечают

Тоже самое текстом для импорта

[{"id":"b05b819f.c4ea5","type":"mqtt in","z":"e60c0f81.64c18","name":"Cpu Temp","topic":"pccpu/retropi","qos":"2","broker":"572eed08.5bb714","x":380,"y":2160,"wires":[["34365a5f.ca6216","d07f2055.bc239"]]},{"id":"34365a5f.ca6216","type":"ui_chart","z":"e60c0f81.64c18","name":"RetroPi Cpu Temp","group":"51bdd67d.76b488","order":2,"width":"0","height":"0","label":"","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"0","dot":false,"ymin":"","ymax":"","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#7c0202","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":550,"y":2160,"wires":[[],[]]},{"id":"d07f2055.bc239","type":"ui_text","z":"e60c0f81.64c18","group":"51bdd67d.76b488","order":1,"width":0,"height":0,"name":"","label":"CPU (Broadcom BCM2836) Temperature","format":"{{msg.payload}}","layout":"col-center","x":650,"y":2120,"wires":[]},{"id":"fdbdadbe.75049","type":"mqtt in","z":"e60c0f81.64c18","name":"Cpu Temp","topic":"pccpu/orangepiplus","qos":"2","broker":"572eed08.5bb714","x":380,"y":2240,"wires":[["f8715fd8.f4c4e","7ac58efe.9836f"]]},{"id":"f8715fd8.f4c4e","type":"ui_chart","z":"e60c0f81.64c18","name":"Orange Pi Pc plus Cpu Temp","group":"c2baeca.d963e1","order":2,"width":0,"height":0,"label":"","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"0","dot":false,"ymin":"","ymax":"","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#7c0202","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":580,"y":2240,"wires":[[],[]]},{"id":"7ac58efe.9836f","type":"ui_text","z":"e60c0f81.64c18","group":"c2baeca.d963e1","order":1,"width":0,"height":0,"name":"","label":"CPU (H3 Quad-core) Temperature","format":"{{msg.payload}}","layout":"col-center","x":630,"y":2200,"wires":[]},{"id":"6eee9129.5375a","type":"mqtt in","z":"e60c0f81.64c18","name":"Cpu Temp1","topic":"pccpu/inteli5c1","qos":"2","broker":"572eed08.5bb714","x":390,"y":2320,"wires":[["2facad3f.7a4302","ee017615.d82cb8"]]},{"id":"2facad3f.7a4302","type":"ui_chart","z":"e60c0f81.64c18","name":"Intel Core Cpu Temp","group":"8007d5e0.fc68a8","order":5,"width":0,"height":0,"label":"Intel Core i5-3470 CPU Temperature","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"0","dot":false,"ymin":"","ymax":"","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#7c0202","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":660,"y":2480,"wires":[[],[]]},{"id":"984b8237.787a6","type":"mqtt in","z":"e60c0f81.64c18","name":"Cpu Temp2","topic":"pccpu/inteli5c2","qos":"2","broker":"572eed08.5bb714","x":390,"y":2380,"wires":[["2facad3f.7a4302","b1d1dca0.453be"]]},{"id":"466f0788.50fb68","type":"mqtt in","z":"e60c0f81.64c18","name":"Cpu Temp3","topic":"pccpu/inteli5c3","qos":"2","broker":"572eed08.5bb714","x":390,"y":2440,"wires":[["2facad3f.7a4302","dd72b678.7599e8"]]},{"id":"75af7157.a1885","type":"mqtt in","z":"e60c0f81.64c18","name":"Cpu Temp4","topic":"pccpu/inteli5c4","qos":"2","broker":"572eed08.5bb714","x":390,"y":2500,"wires":[["2facad3f.7a4302","39fcaaab.85efa6"]]},{"id":"ee017615.d82cb8","type":"ui_text","z":"e60c0f81.64c18","group":"8007d5e0.fc68a8","order":1,"width":0,"height":0,"name":"","label":"Core 1 Temperature","format":"{{msg.payload}}","layout":"row-center","x":660,"y":2320,"wires":[]},{"id":"b1d1dca0.453be","type":"ui_text","z":"e60c0f81.64c18","group":"8007d5e0.fc68a8","order":2,"width":0,"height":0,"name":"","label":"Core 2 Temperature","format":"{{msg.payload}}","layout":"row-center","x":660,"y":2360,"wires":[]},{"id":"dd72b678.7599e8","type":"ui_text","z":"e60c0f81.64c18","group":"8007d5e0.fc68a8","order":3,"width":0,"height":0,"name":"","label":"Core 3 Temperature","format":"{{msg.payload}}","layout":"row-center","x":660,"y":2400,"wires":[]},{"id":"39fcaaab.85efa6","type":"ui_text","z":"e60c0f81.64c18","group":"8007d5e0.fc68a8","order":4,"width":0,"height":0,"name":"","label":"Core 4 Temperature","format":"{{msg.payload}}","layout":"row-center","x":660,"y":2440,"wires":[]},{"id":"572eed08.5bb714","type":"mqtt-broker","z":"","name":"Mosquitto Orange","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"51bdd67d.76b488","type":"ui_group","z":"","name":"RetroPi","tab":"69d311f6.b104c","order":1,"disp":true,"width":"12","collapse":false},{"id":"c2baeca.d963e1","type":"ui_group","z":"","name":"Orange Pi PC PLUS","tab":"69d311f6.b104c","order":2,"disp":true,"width":"12","collapse":false},{"id":"8007d5e0.fc68a8","type":"ui_group","z":"","name":"Intel PC","tab":"69d311f6.b104c","order":3,"disp":true,"width":"12","collapse":false},{"id":"69d311f6.b104c","type":"ui_tab","z":"","name":"CPU Temperature","icon":"dashboard","order":3}]

Вот такие графики демонстрируеются за 24 часа.

Действия для RaspberryPi 3 на RetroPi и Orange Pi PC PLUS на Armbian по настйроке отличаются только названием топика в который будем посылать значение температуры

ставим
sudo apt-get install mosquitto-clients
идем в папку
cd /home/pi
добавляем в файл
vi sendtemp.sh
строчки

#!/bin/bash
a=`cat /sys/class/thermal/thermal_zone0/temp`
d=$(( ${a}/1000 ))
/usr/bin/mosquitto_pub -h "192.168.1.209" -u Login -P MyPassword -t "pccpu/retropi" -m "${d}"

Делаем исполняем
chmod +x sendtemp.sh
И добавлем в расписание
crontab -e
строчку

* * * * * sh /home/pi/sendtemp.sh

Все тоже самое для Апельсинки только вместо pccpu/retropi надо ставить pccpu/orangepiplus ну и путь к срипту

Теперь для интеловского пк на Ubuntu, тут не так просто получить температуру она для каждого ядра разная
ставим
sudo apt-get install mosquitto-clients
и для сенсоров
sudo apt-get install lm-sensors
sudo sensors-detect

И смотрим какие датчики есть, их даже больше чем надо
sudo sensors -u
идем в свою домашнею папку
cd /home/user
добавляем в файл
sudo vi sendtemp.sh
строчки

#!/bin/bash
c1=`sensors -u *-isa-* | grep "temp2_input:" | awk '{printf "%.0f", $2}'`
/usr/bin/mosquitto_pub -h "192.168.1.209" -u Login -P MyPassword -t "pccpu/inteli5c1" -m "${c1}"
c1=`sensors -u *-isa-* | grep "temp3_input:" | awk '{printf "%.0f", $2}'`
/usr/bin/mosquitto_pub -h "192.168.1.209" -u Login -P MyPassword -t "pccpu/inteli5c2" -m "${c1}"
c1=`sensors -u *-isa-* | grep "temp4_input:" | awk '{printf "%.0f", $2}'`
/usr/bin/mosquitto_pub -h "192.168.1.209" -u Login -P MyPassword -t "pccpu/inteli5c3" -m "${c1}"
c1=`sensors -u *-isa-* | grep "temp5_input:" | awk '{printf "%.0f", $2}'`
/usr/bin/mosquitto_pub -h "192.168.1.209" -u Login -P MyPassword -t "pccpu/inteli5c4" -m "${c1}"

Делаем исполняем
sudo chmod +x sendtemp.sh
И добавляем в расписание
sudo crontab -e
строчку

* * * * * sh /home/user/sendtemp.sh

Работает