ESP8266 Aquarium Controller Part 3
Now that all the hardware is put together (Step 1 and Step 2), it’s time to program the ESP8266.
This is a pretty versatile device and you can make it do just about anything you want. You could add some buttons and dials to control the relays and set timers and make the controller completely autonomous. In my case, I already have a Home Assistant controller so I only needed this new controller to be remotely controllable.
The code at the end of this article sets up the ESP8266 to be an MQTT client. It communicates with Home Assistant through a MQTT server/broker using its built in wifi chip. It publishes the following information:
- aquarium/1/relayHeater/set
- aquarium/1/relayLight/set
- aquarium/1/relayCO2/set
- aquarium/1/rssi (this is the wifi signal strength)
The code also checks for the following payloads:
- aquarium/1/relayHeater
- aquarium/1/relayLight
- aquarium/1/relayCO2
Before compiling and uploading the code, you will need to insert the following information:
- WiFi SSID
- Wifi Password
- MQTT Server IP Address
- MQTT User ID
- MQTT Password
You can also edit the Client_ID (must be unique) and the MQTT_Topic.
Once everything is compiled and loaded onto the ESP8266, you’ll probably want to monitor it through the serial monitor to make sure it’s working correctly. If it looks good you can disconnect it from your PC and power it through the USB adapter that you installed in Step 2.
Setting Up Home Assistant
You can use anything that’s compatible with MQTT to monitor and control your new aquarium controller. In my case, I’m using Home Assistant with the MQTT addon so I can integrate the aquarium with all my other automations and interfaces.
First you’ll need to add MQTT to Home Assistant. There are many guides out there so I won’t go into it here. After that, simply add the following to your configuration.yaml file and reboot:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
sensor: - platform: mqtt state_topic: 'aquarium/1/temp' name: 'Aquarium 1 Temperature' unit_of_measurement: '°C' - platform: mqtt state_topic: 'aquarium/1/rssi' name: 'Aquarium 1 RSSI' unit_of_measurement: "dBm" switch: - platform: mqtt name: "Aquarium 1 Heater" state_topic: "aquarium/1/relayHeater" command_topic: "aquarium/1/relayHeater/set" payload_off: "0" payload_on: "1" qos: 1 - platform: mqtt name: "Aquarium 1 Light" state_topic: "aquarium/1/relayLight" command_topic: "aquarium/1/relayLight/set" payload_off: "0" payload_on: "1" qos: 1 - platform: mqtt name: "Aquarium 1 CO2" state_topic: "aquarium/1/relayCO2" command_topic: "aquarium/1/relayCO2/set" payload_off: "0" payload_on: "1" qos: 1 climate: - platform: generic_thermostat name: Aquarium1 heater: switch.aquarium_1_heater target_sensor: sensor.aquarium_1_temperature hot_tolerance: 0.6 precision: 0.1 |

Now you should have two new sensors – one for the aquarium’s temperature and another one for the aquarium controller’s wifi strength.
You’ll also have three new switches: Light, Heater, and CO2.

And for convenience, I also combined the heater switch and the temperature sensor into a new generic thermostat. Now it can be controlled easily through the Lovelace UI or even through Google Assistant.

I set up my UI using a Horizontal Stack and Glance card. Pressing/clicking on the icons pops up their history and a switch to turn them on or off.
Now you can add the new entities to your automations and your UI. Enjoy!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
#include <ESP8266WiFi.h> #include <PubSubClient.h> #include <ArduinoOTA.h> float rssi; // To measure signal strength int rssiinterval = 10000; // ms interval between checkups long lastrssi = 0; // counter for non-interupt measurement #include <OneWire.h> #include <DallasTemperature.h> #define ONE_WIRE_BUS D4 // DS18B20 pin OneWire oneWire(ONE_WIRE_BUS); DallasTemperature DS18B20(&oneWire); int checkinterval = 15000; // ms interval between checkups (smaller than 6 seconds makes it unstable) long lastMsg = 0; // counter for non-interupt measurement // Update these with values suitable for your network. const char* ssid = "your wifi ssid here"; const char* password = "your wifi password here"; const char* mqtt_server = "your MQTT ip address here"; int mqttport = 1883; #define CLIENT_ID "aq1" //has to be unique in your system #define MQTT_TOPIC "aquarium/1" char* uid = "MQTT user ID"; char* pw = "MQTT password"; WiFiClient espClient; PubSubClient client(espClient); #define relayHeater D2 #define relayLight D3 #define relayCO2 D5 const char* topic_relayHeater = MQTT_TOPIC"/relayHeater/set"; const char* topic_relayLight = MQTT_TOPIC"/relayLight/set"; const char* topic_relayCO2 = MQTT_TOPIC"/relayCO2/set"; int light = 0; void setup(){ Serial.begin(9600); Serial.println("setup begin"); pinMode(LED_BUILTIN, OUTPUT); DS18B20.begin(); pinMode(relayHeater, OUTPUT); pinMode(relayLight, OUTPUT); pinMode(relayCO2, OUTPUT); delay(10); // start relays in the off position (may need to use LOW for your relays) digitalWrite(relayHeater, HIGH); digitalWrite(relayLight, HIGH); digitalWrite(relayCO2, HIGH); digitalWrite(LED_BUILTIN, HIGH); // test relays for 1 second digitalWrite(LED_BUILTIN, LOW); delay(1000); digitalWrite(LED_BUILTIN, HIGH); digitalWrite(relayHeater, LOW); delay(1000); digitalWrite(relayHeater, HIGH); digitalWrite(relayLight, LOW); delay(1000); digitalWrite(relayLight, HIGH); digitalWrite(relayCO2, LOW); delay(1000); digitalWrite(relayCO2, HIGH); //start wifi and mqqt setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); // OTA setup ArduinoOTA.setHostname(CLIENT_ID); ArduinoOTA.onStart([]() { Serial.println("Start"); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); Serial.println("setup end"); } void loop(){ ArduinoOTA.handle(); // Connect to Wifi if not connected if (WiFi.status() != WL_CONNECTED) { setup_wifi(); reconnect(); client.setServer(mqtt_server, mqttport); client.setCallback(callback); } else { //if connected get RSSI (Wifi signal strengt) from ESP8266 and publish it to MQTT checkrssi(); } // reconnect when MQTT is not connected if (!client.connected()) { reconnect(); } client.loop(); // temperature checktemp(); } void checktemp(){ long now = millis(); // only check every x ms checkinterval if (now - lastMsg > checkinterval) { lastMsg = now; DS18B20.requestTemperatures(); String temps1 = String(DS18B20.getTempCByIndex(0)); float t = temps1.toFloat(); // to add more sensors you would do the following: // String temps2 = String(DS18B20.getTempCByIndex(1)); // float t2 = temps2.toFloat(); Serial.print("Temp1: "); Serial.println(t); if (client.connected()) { client.publish(MQTT_TOPIC"/temp", String(t).c_str(), false); } } } void setup_wifi() { delay(10); // Start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); //ESP in connect to network mode WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { // wait 50 * 10 ms = 500 ms to give ESP some time to connect (need to delay or else you get soft WDT reset) for (int i=0; i <= 50; i++){ delay(10); if (i == 50) { Serial.println("."); } else { Serial.print("."); } } } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); digitalWrite(LED_BUILTIN, HIGH); //LED off } 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(); //switch on relayHeater LED if topic is correct and 1 is received if (strcmp(topic, topic_relayHeater)==0){ if ((char)payload[0] == '1') { digitalWrite(relayHeater, LOW); //on client.publish(MQTT_TOPIC"/relayHeater", "1", true); } else { digitalWrite(relayHeater, HIGH); //off client.publish(MQTT_TOPIC"/relayHeater", "0", true); } } //switch on relayLight LED if topic is correct and 1 is received if (strcmp(topic, topic_relayLight)==0){ if ((char)payload[0] == '1') { digitalWrite(relayLight, LOW); //on client.publish(MQTT_TOPIC"/relayLight", "1", true); } else { digitalWrite(relayLight, HIGH); //off client.publish(MQTT_TOPIC"/relayLight", "0", true); } } //switch on relayCO2 LED if topic is correct and 1 is received if (strcmp(topic, topic_relayCO2)==0){ if ((char)payload[0] == '1') { client.publish(MQTT_TOPIC"/relayCO2", "1", true); digitalWrite(relayCO2, LOW); //on } else { client.publish(MQTT_TOPIC"/relayCO2", "0", true); digitalWrite(relayCO2, HIGH); //off } } } void reconnect() { // Loop until we're reconnected digitalWrite(LED_BUILTIN, LOW); //LED on while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect(CLIENT_ID, uid, pw)) { Serial.println("connected"); //subscribe to the following topics client.subscribe(MQTT_TOPIC"/relayHeater/set"); client.subscribe(MQTT_TOPIC"/relayLight/set"); client.subscribe(MQTT_TOPIC"/relayCO2/set"); digitalWrite(LED_BUILTIN, HIGH); //LED off } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait (500 * 10ms = 5000ms) 5 seconds before retrying for (int i=0; i <= 500; i++){ delay(10); if (i == 50) { Serial.println("."); } else { Serial.print("."); } } } } } void checkrssi(){ long nowrssi = millis(); // only check every x ms checkinterval if (nowrssi - lastrssi > rssiinterval) { lastrssi = nowrssi; // measure RSSI float rssi = WiFi.RSSI(); // make RSSI -100 if long rssi is not between -100 and 0 if (rssi < -100 && rssi > 0){ rssi = -110; } Serial.print("RSSI = "); Serial.println(rssi); if (client.connected()) { client.publish(MQTT_TOPIC"/rssi", String(rssi).c_str(), false); } } } |