/*
|
|
main_pilot_wire_control.ino
|
|
Switches on or off several heaters.
|
|
*/
|
|
|
|
#include <Ticker.h>
|
|
|
|
#include "EspMQTTClient.h"
|
|
|
|
#define LWD_TIMEOUT_MS 15000
|
|
|
|
EspMQTTClient client(
|
|
"rico2",
|
|
"xxxxx",
|
|
"192.168.1.2", // MQTT Broker server ip
|
|
"", // Can be omitted if not needed
|
|
"", // Can be omitted if not needed
|
|
"pilote-general", // Client name that uniquely identify your device
|
|
1883 // The MQTT port, default to 1883. this line can be omitted
|
|
);
|
|
|
|
enum rooms {
|
|
LIVING_ROOM,
|
|
ROOM_SO,
|
|
ROOM_RICO,
|
|
BATHROOM,
|
|
NB_HEATERS
|
|
};
|
|
|
|
struct heater {
|
|
int pin;
|
|
enum rooms room;
|
|
const char *topic;
|
|
MessageReceivedCallback callback;
|
|
os_timer_t keep_alive_timer;
|
|
};
|
|
|
|
static struct heater heaters[NB_HEATERS];
|
|
|
|
const int led_pin = 2;
|
|
|
|
#define led_on(state) do {\
|
|
digitalWrite(led_pin, (state) ? LOW : HIGH); \
|
|
} while (0)
|
|
|
|
#define heater_on(pin) do {\
|
|
digitalWrite(pin, LOW); \
|
|
} while(0)
|
|
|
|
#define heater_off(pin) do {\
|
|
digitalWrite(pin, HIGH); \
|
|
} while(0)
|
|
|
|
// loop watchdog variables
|
|
unsigned long lwdTime = 0;
|
|
unsigned long lwdTimeout = LWD_TIMEOUT_MS;
|
|
Ticker lwdTicker;
|
|
|
|
void reset_timer(enum rooms room)
|
|
{
|
|
os_timer_t *timer = &(heaters[room].keep_alive_timer);
|
|
|
|
os_timer_disarm(timer);
|
|
os_timer_setfn(timer, shutdown_heater, &(heaters[room].room));
|
|
os_timer_arm(timer, 3600000, false);
|
|
}
|
|
|
|
void ICACHE_RAM_ATTR lwdtcb(void)
|
|
{
|
|
if (((millis() - lwdTime) > LWD_TIMEOUT_MS) || ((lwdTimeout - lwdTime) != LWD_TIMEOUT_MS))
|
|
{
|
|
ESP.restart();
|
|
}
|
|
}
|
|
|
|
void lwdtFeed(void) {
|
|
lwdTime = millis();
|
|
lwdTimeout = lwdTime + LWD_TIMEOUT_MS;
|
|
}
|
|
|
|
void handle_message(enum rooms room, const String &message)
|
|
{
|
|
Serial.println(message);
|
|
if (message.equals("0") || message.equalsIgnoreCase("off") || message.equalsIgnoreCase("false")) {
|
|
heater_off(heaters[room].pin);
|
|
}
|
|
if (message.equals("1") || message.equalsIgnoreCase("on") || message.equalsIgnoreCase("true")) {
|
|
heater_on(heaters[room].pin);
|
|
}
|
|
reset_timer(room);
|
|
}
|
|
|
|
void living_room_callback(const String &message)
|
|
{
|
|
handle_message(LIVING_ROOM, message);
|
|
}
|
|
|
|
void room_so_callback(const String &message)
|
|
{
|
|
handle_message(ROOM_SO, message);
|
|
}
|
|
|
|
void room_rico_callback(const String &message)
|
|
{
|
|
handle_message(ROOM_RICO, message);
|
|
}
|
|
|
|
void bathroom_callback(const String &message)
|
|
{
|
|
handle_message(BATHROOM, message);
|
|
}
|
|
|
|
void shutdown_heater(void *arg)
|
|
{
|
|
enum rooms room = *(enum rooms *)arg;
|
|
|
|
// if we didn't receive a message for an hour,
|
|
// shutdown the heater
|
|
Serial.print("No MQTT message for one hour on topic ");
|
|
Serial.print(heaters[room].topic);
|
|
Serial.println(", switching off.");
|
|
heater_off(heaters[room].pin);
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
unsigned i;
|
|
|
|
heaters[LIVING_ROOM].room = LIVING_ROOM;
|
|
heaters[ROOM_SO].room = ROOM_SO;
|
|
heaters[ROOM_RICO].room = ROOM_RICO;
|
|
heaters[BATHROOM].room = BATHROOM;
|
|
|
|
heaters[LIVING_ROOM].pin = 4;
|
|
heaters[ROOM_SO].pin = 14;
|
|
heaters[ROOM_RICO].pin = 12;
|
|
heaters[BATHROOM].pin = 13;
|
|
|
|
heaters[LIVING_ROOM].topic = "chauffage/salon";
|
|
heaters[ROOM_SO].topic = "chauffage/chambre_rico";
|
|
heaters[ROOM_RICO].topic = "chauffage/chambre_so";
|
|
heaters[BATHROOM].topic = "chauffage/sdb";
|
|
|
|
heaters[LIVING_ROOM].callback = living_room_callback;
|
|
heaters[ROOM_SO].callback = room_so_callback;
|
|
heaters[ROOM_RICO].callback = room_rico_callback;
|
|
heaters[BATHROOM].callback = bathroom_callback;
|
|
|
|
for (i = 0; i < NB_HEATERS; i++) {
|
|
pinMode(heaters[i].pin, OUTPUT);
|
|
heater_off(heaters[i].pin);
|
|
}
|
|
|
|
pinMode(led_pin, OUTPUT);
|
|
|
|
Serial.begin(115200);
|
|
|
|
// Optionnal functionnalities of EspMQTTClient :
|
|
client.enableDebuggingMessages(); // Enable debugging messages sent to serial output
|
|
client.enableHTTPWebUpdater(); // Enable the web updater. User and password default to values of MQTTUsername and MQTTPassword. These can be overrited with enableHTTPWebUpdater("user", "password").
|
|
for (i = 0; i < NB_HEATERS; i++) {
|
|
os_timer_setfn(&(heaters[i].keep_alive_timer), shutdown_heater, &(heaters[i].room));
|
|
os_timer_arm(&(heaters[i].keep_alive_timer), 3600000, false);
|
|
}
|
|
}
|
|
|
|
// This function is called once everything is connected (Wifi and MQTT)
|
|
// WARNING : YOU MUST IMPLEMENT IT IF YOU USE EspMQTTClient
|
|
void onConnectionEstablished()
|
|
{
|
|
for (unsigned i = 0; i < NB_HEATERS; i++) {
|
|
client.subscribe(heaters[i].topic, heaters[i].callback);
|
|
}
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
static unsigned int counter;
|
|
static bool led_state = false;
|
|
|
|
client.loop();
|
|
if (!client.isConnected()) {
|
|
// if something wrong happens, switch off the heater
|
|
for (unsigned i = 0; i < NB_HEATERS; i++) {
|
|
heater_off(heaters[i].pin);
|
|
}
|
|
}
|
|
|
|
// blink ESP blue led to show that we are alive
|
|
if (((led_state) && (counter % 1000 == 0)) || (!led_state && (counter % 30000 == 0))) {
|
|
led_state = !led_state;
|
|
led_on(led_state);
|
|
}
|
|
counter++;
|
|
lwdtFeed();
|
|
}
|