Использование протокола MQTT в «Умном доме». Часть 2 - датчик LM19 и реле
25 Dec 2018Arduino скетч для работы с MQTT брокером. В этом скетче используется датчик температуры LM19 и 3-и relay модуля.
/*
Arduino MQTT Relay Contorol
В качестве датчика температуры в данном примере используется LM19.
*/
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xFF };
char macstr[] = "deadbeeffeff";
byte ip[] = {192, 168, 0, 179 };
byte gateway[] = { 192, 168, 0, 1 };
byte subnet[] = { 255, 255, 255, 0 };
String clientName = String("arduino-179_") + macstr;
String topicTempName = String("/ard-179/temperature1");
// mqtt брокер
#define mqtt_server "192.168.0.170"
// порт подключения к mqtt
#define mqtt_port 1883
// Длинна имени топика обязательно 15 символов, для этого примера, иначе внести изменения в функцию callback()
#define mqtt_topic1 "/ard-179/relay1"
#define mqtt_topic2 "/ard-179/relay2"
#define mqtt_topic3 "/ard-179/relay3"
float tempF = 0.0;
float tempC = 0.0;
float humidity = 0.0;
EthernetClient ethClient;
PubSubClient client(ethClient);
const int domRelay1 = A1;
const int domRelay2 = A2;
const int domRelay3 = A3;
long lastMsg = 0;
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic); // отправляем в монитор порта название топика
Serial.print("] ");
for (int i = 0; i < length; i++) { // отправляем данные из топика
Serial.print((char)payload[i]);
}
Serial.println();
// работаем с реле
if (topic[14] == '1') { // 15-ый символ массива номер реле
if (payload[0] == '0') digitalWrite(domRelay1, LOW);
else if (payload[0] == '1') digitalWrite(domRelay1, HIGH);
else if (payload[0] == '2') digitalWrite(domRelay1, !digitalRead(domRelay1));
// Serial.println("Relay1");
} else if (topic[14] == '2') {
if (payload[0] == '0') digitalWrite(domRelay2, LOW);
else if (payload[0] == '1') digitalWrite(domRelay2, HIGH);
else if (payload[0] == '2') digitalWrite(domRelay2, !digitalRead(domRelay2));
// Serial.println("Relay2");
} else if (topic[14] == '3') {
if (payload[0] == '0') digitalWrite(domRelay3, LOW);
else if (payload[0] == '1') digitalWrite(domRelay3, HIGH);
else if (payload[0] == '2') digitalWrite(domRelay3, !digitalRead(domRelay3));
// Serial.println("Relay3");
}
}
// подключение к mqtt брокеру
void reconnect() {
while (!client.connected()) { // крутимся пока не подключимся.
Serial.print("Attempting MQTT connection...");
char clientStr[34];
clientName.toCharArray(clientStr,34);
// подключаемся, в client.connect передаем ID, логин и пасс
if (client.connect(clientStr)) {
Serial.println("connected"); // если подключились
client.subscribe(mqtt_topic1); // подписываемся на топик 1-го реле, в который же пишем данные
client.subscribe(mqtt_topic2); // подписываемся на топик 2-го реле, в который же пишем данные
client.subscribe(mqtt_topic3); // подписываемся на топик 3-го реле, в который же пишем данные
} else { // иначе ругаемся в монитор порта
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Ждем 5 секунд до следующей попытки
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
pinMode(domRelay1, OUTPUT);
digitalWrite(domRelay1, LOW);
pinMode(domRelay2, OUTPUT);
digitalWrite(domRelay2, LOW);
pinMode(domRelay3, OUTPUT);
digitalWrite(domRelay3, LOW);
Ethernet.begin(mac, ip);
client.setServer(mqtt_server, mqtt_port); // указываем адрес брокера и порт
client.setCallback(callback); // указываем функцию которая вызывается когда приходят данные от брокера
}
void loop() {
if (!client.connected()) { // проверяем подключение к брокеру
reconnect();
}
client.loop();
long now = millis(); // каждые 10 секунд выполняем публиукцию температуры на брокере
if (now - lastMsg > 10000) {
lastMsg = now;
getTemperatureData();
String json = buildJson();
char jsonStr[200];
json.toCharArray(jsonStr,200);
char topicStr[26];
topicTempName.toCharArray(topicStr,26);
boolean pubresult = client.publish(topicStr,jsonStr);
Serial.print("attempt to send ");
Serial.println(jsonStr);
}
}
/////////////////////////////////////////////////////////
String buildJson() {
String data = "{";
data+= "\"d\": {";
data+="\"SensorName\": \"LM19\",";
data+="\"temperature\": ";
data+=(float)tempC;
data+= ",";
data+="\"humidity\": ";
data+=(float)humidity;
data+="}";
data+="}";
return data;
}
void getTemperatureData() {
float vin = 5.0 * analogRead(0) / 1024.0;
tempC = (1.8663 - vin) / 0.01169;
tempF = 1.8 * tempC + 32.0;
}
Дополнительно. Работа с датчиком LM19
LM19 является аналоговым датчиком температуры, который работает в определенном температурном диапазоне (от -55 до 130 по Цельсию). Его очень легко связать с микроконтроллером благодаря достаточно линейному выходному напряжению.
В следующем листинге кода показано, как получить показания температуры с датчика LM19 на Arduino. Код предполагает, что выход датчика подключен к аналоговому контакту 0.
void setup()
{
Serial.begin(9600);
}
void loop()
{
float vin = 5.0 * analogRead(0) / 1024.0;
Serial.print(vin);
Serial.print(" ");
float tempC = (1.8663 - vin) / 0.01169;
float tempF = 1.8 * tempC + 32.0;
Serial.print(tempC);
Serial.print(" ");
Serial.println(tempF);
delay(100);
}
В приведенном выше коде использована приближенная линейная функциия, показанная ниже. Это довольно точно, когда температурный диапазон составляет около комнатной температуры.

Для более точного измерения температуры во всем рабочем диапазоне можно использовать следующее уравнение:
