Today I will show you how to build a Smart Home with Home Assistant (HA) using Raspberry Pi and ESP32/ESP8266.
Home Assistant will act as a server with GUI and ESP32/ESP8266 as clients. User will access Home Assistant by web browser with url: http://homeassistant.local:8123 or http://IP_address:8123
Figure: Startup Disk Creator
- Waiting until the image is written to SD card.
- Plug the SD card to Raspberry Pi.
- Power up the Raspberry Pi and connect it to your LAN network by network cable.
2.2 Setup Ethernet, Wifi
If you only have Wifi and have no Wired connection hole, you can configure your laptop as a bridge (like hotspot) like below:
Pi -> network cable -> laptop -> Wifi
- For the first time, Home Assistant takes quite long time to startup (about ~15-20 minutes).
- Create account
- Choose Next and FinishSetup Wifi
From left Menu choose Supervisor > IP Address Change > WLAN0 > IPv4 > DHCP > Wi-Fi > SCAN FOR ACCESSPOINTS > wpa-psk > Password > Save > REBOOT
2.3 Install necessary software
From left Menu choose Supervisor > Add-on Store
then press Install and press Start button:
Mosquitto broker
File editor
This application supports to modify *.yaml (choose Show in sidebar to add the add-on to the upper left Menu)
Install Grafana
choose File Browser (red circle)
sensor: - platform: mqtt state_topic: 'home/room/temperature' name: 'Room Temperature' unit_of_measurement: '°C'
#include <WiFi.h> #include <PubSubClient.h> #include <ESPmDNS.h> /* change it with your ssid-password */ const char* ssid = "I3.41"; const char* password = "xxx"; /* this is the IP of PC/raspberry where you installed MQTT Server */ const char* mqtt_server = "homeassistant"; #define mqtt_user "iotsharing" #define mqtt_password "xyz" #define mqtt_clientId "iotsharing-sensor" float temperature = 0; /* create an instance of PubSubClient client */ WiFiClient espClient; PubSubClient client(espClient); /* topics */ #define TEMP_TOPIC "home/room/temperature" long lastMsg = 0; char msg[20]; void reconnect() { //Loop until we're reconnected while (!client.connected()) { if (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) { Serial.println("connected"); delay(1000); Serial.print("MQTT connected!"); } else { Serial.print("failed, rc="); Serial.print(client.state()); } } } void setup() { Serial.begin(115200); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); if (!MDNS.begin("esp32")) { Serial.println("Error setting up MDNS responder!"); while(1) { delay(1000); } } IPAddress serverIp = MDNS.queryHost(mqtt_server); Serial.print("IP address of server: "); Serial.println(serverIp.toString()); /* configure the MQTT server with IPaddress and port */ client.setServer(serverIp, 1883); } void loop() { /* if client was disconnected then try to reconnect again */ if (!client.connected()) { reconnect(); } /* this function will listen for incomming subscribed topic-process-invoke receivedCallback */ client.loop(); /* we measure temperature every 3 secs we count until 3 secs reached to avoid blocking program if using delay()*/ long now = millis(); if (now - lastMsg > 3000) { lastMsg = now; /* read DHT11/DHT22 sensor and convert to string */ temperature = random(20,40)/1.0; if (!isnan(temperature)) { snprintf (msg, 20, "%lf", temperature); Serial.println(msg); /* publish the message */ client.publish(TEMP_TOPIC, msg); } } }
switch: - platform: mqtt name: "Light" state_topic: "home/room/switch/set" command_topic: "home/room/switch/set" payload_on: "on" payload_off: "off" qos: 0
#include <WiFi.h> #include <PubSubClient.h> #include <ESPmDNS.h> /* change it with your ssid-password */ const char* ssid = "I3.41"; const char* password = "xxx"; /* this is the IP of PC/raspberry where you installed MQTT Server */ const char* mqtt_server = "homeassistant"; #define mqtt_user "iotsharing" #define mqtt_password "xyz" #define mqtt_clientId "iotsharing-sensor" float temperature = 0; /* create an instance of PubSubClient client */ WiFiClient espClient; PubSubClient client(espClient); /* topics */ #define CTRL_BULB_TOPIC "home/room/switch/set" long lastMsg = 0; char msg[20]; void reconnect() { //Loop until we're reconnected while (!client.connected()) { if (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) { Serial.println("connected"); delay(1000); Serial.print("MQTT connected!"); client.subscribe(CTRL_BULB_TOPIC); } else { Serial.print("failed, rc="); Serial.print(client.state()); } } } void receivedCallback(char* topic, byte* payload, unsigned int length) { Serial.print("Message received: "); Serial.print("payload: "); String cmd = ""; for (int i = 0; i < length; i++) { cmd += (char)payload[i]; } Serial.print("HA control bulb: "); Serial.println(cmd); } void setup() { Serial.begin(115200); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); if (!MDNS.begin("esp32")) { Serial.println("Error setting up MDNS responder!"); while(1) { delay(1000); } } IPAddress serverIp = MDNS.queryHost(mqtt_server); Serial.print("IP address of server: "); Serial.println(serverIp.toString()); /* configure the MQTT server with IPaddress and port */ client.setServer(serverIp, 1883); client.setCallback(receivedCallback); } void loop() { /* if client was disconnected then try to reconnect again */ if (!client.connected()) { reconnect(); } /* this function will listen for incomming subscribed topic-process-invoke receivedCallback */ client.loop(); }
influxdb: host: localhost port: 8086 database: myhome username: iotsharing password: xyz default_measurement: state include: entities: - sensor.room_temperator
#include <WiFi.h> #include <PubSubClient.h> #include "ArduinoJson.h" #include <ESPmDNS.h> #define wifi_ssid "I3.41" #define wifi_password "xxx" #define mqtt_server "homeassistant" #define mqtt_user "iotsharing" #define mqtt_password "yyy" #define mqtt_clientId "iotsharing-sensor" //The discovery topic need to follow a specific format: // <discovery_prefix>/<component>/[<node_id>/]<object_id>/config #define TOPIC_TEMP_CONF "homeassistant/sensor/iotsharing/iotsharing_temp/config" #define TOPIC_PRESS_CONF "homeassistant/switch/iotsharing/iotsharing_light/config" #define TEMP_STATE "homeassistant/sensor/iotsharing/temp_state" #define LIGHT_STATE "homeassistant/switch/iotsharing/light_state" #define CMD_LIGHT_STATE "homeassistant/switch/iotsharing/light_state/set" #define TEMP_NAME "IOTSHARING TEMP" #define TEMP_CLASS "temperature" #define LIGHT_NAME "IOTSHARING LIGHT" //variables WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; float temp = 0.00; float pressure = 0.00; //functions void publishTempConfig() { const size_t bufferSize = JSON_OBJECT_SIZE(8); DynamicJsonBuffer jsonBuffer(bufferSize); JsonObject& root = jsonBuffer.createObject(); root["name"] = TEMP_NAME; root["dev_cla"] = TEMP_CLASS; root["stat_t"] = TEMP_STATE; root["unit_of_meas"] = "°C"; root["val_tpl"] = "{{value_json.temperature}}"; root.prettyPrintTo(Serial); Serial.println(""); char message[256]; root.printTo(message, sizeof(message)); client.publish(TOPIC_TEMP_CONF, message, true); } void publishLightConfig() { const size_t bufferSize = JSON_OBJECT_SIZE(8); DynamicJsonBuffer jsonBuffer(bufferSize); JsonObject& root = jsonBuffer.createObject(); root["name"] = LIGHT_NAME; root["stat_t"] = LIGHT_STATE; root["cmd_t"] = CMD_LIGHT_STATE; root["pl_on"] = "on"; root["pl_off"] = "off"; root.prettyPrintTo(Serial); Serial.println(""); char message[256]; root.printTo(message, sizeof(message)); client.publish(TOPIC_PRESS_CONF, message, true); } void setup_wifi() { delay(10); Serial.println(); Serial.print("Connecting to "); Serial.println(wifi_ssid); WiFi.begin(wifi_ssid, wifi_password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void reconnect() { //Loop until we're reconnected while (!client.connected()) { if (client.connect(mqtt_clientId, mqtt_user, mqtt_password)) { Serial.println("connected"); delay(1000); publishTempConfig(); delay(1000); publishLightConfig(); delay(500); client.subscribe(CMD_LIGHT_STATE); Serial.print("MQTT connected!"); } else { Serial.print("failed, rc="); Serial.print(client.state()); } } } void receivedCallback(char* topic, byte* payload, unsigned int length) { Serial.print("Message received: "); Serial.print("payload: "); String cmd = ""; for (int i = 0; i < length; i++) { cmd += (char)payload[i]; } Serial.println(cmd); if(cmd == "on"){ client.publish(LIGHT_STATE, "on"); } else { client.publish(LIGHT_STATE, "off"); } } void publishData(float p_temperature) { const size_t bufferSize = JSON_OBJECT_SIZE(2); DynamicJsonBuffer jsonBuffer(bufferSize); JsonObject& root = jsonBuffer.createObject(); root["temperature"] = (String)p_temperature; //root.prettyPrintTo(Serial); char data[74]; root.printTo(data, sizeof(data)); client.publish(TEMP_STATE, data, true); } void setup() { Serial.begin(115200); delay(10); setup_wifi(); if (!MDNS.begin("esp32")) { Serial.println("Error setting up MDNS responder!"); while(1) { delay(1000); } } IPAddress serverIp = MDNS.queryHost(mqtt_server); Serial.print("IP address of server: "); Serial.println(serverIp.toString()); client.setServer(serverIp, 1883); client.setCallback(receivedCallback); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); long now = millis(); if(now - lastMsg > 5000) { lastMsg = now; if (!client.connected()) { reconnect(); } temp = (float)random(10, 50); publishData(temp); } }
camera: - platform: mjpeg name: Livingroom Camera mjpeg_url: http://ip_of_esp_cam/video
#include "esp_camera.h" #include <WiFi.h> #define PWDN_GPIO_NUM 32 #define RESET_GPIO_NUM -1 #define XCLK_GPIO_NUM 0 #define SIOD_GPIO_NUM 26 #define SIOC_GPIO_NUM 27 #define Y9_GPIO_NUM 35 #define Y8_GPIO_NUM 34 #define Y7_GPIO_NUM 39 #define Y6_GPIO_NUM 36 #define Y5_GPIO_NUM 21 #define Y4_GPIO_NUM 19 #define Y3_GPIO_NUM 18 #define Y2_GPIO_NUM 5 #define VSYNC_GPIO_NUM 25 #define HREF_GPIO_NUM 23 #define PCLK_GPIO_NUM 22 WiFiServer server(80); bool connected = false; WiFiClient live_client; String index_html = "<meta charset=\"utf-8\"/>\n" \ "<style>\n" \ "#content {\n" \ "display: flex;\n" \ "flex-direction: column;\n" \ "justify-content: center;\n" \ "align-items: center;\n" \ "text-align: center;\n" \ "min-height: 100vh;}\n" \ "</style>\n" \ "<body bgcolor=\"#000000\"><div id=\"content\"><h2 style=\"color:#ffffff\">HTTP ESP32 Cam live stream </h2><img src=\"video\"></div></body>"; void configCamera(){ camera_config_t config; config.ledc_channel = LEDC_CHANNEL_0; config.ledc_timer = LEDC_TIMER_0; config.pin_d0 = Y2_GPIO_NUM; config.pin_d1 = Y3_GPIO_NUM; config.pin_d2 = Y4_GPIO_NUM; config.pin_d3 = Y5_GPIO_NUM; config.pin_d4 = Y6_GPIO_NUM; config.pin_d5 = Y7_GPIO_NUM; config.pin_d6 = Y8_GPIO_NUM; config.pin_d7 = Y9_GPIO_NUM; config.pin_xclk = XCLK_GPIO_NUM; config.pin_pclk = PCLK_GPIO_NUM; config.pin_vsync = VSYNC_GPIO_NUM; config.pin_href = HREF_GPIO_NUM; config.pin_sscb_sda = SIOD_GPIO_NUM; config.pin_sscb_scl = SIOC_GPIO_NUM; config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; config.pixel_format = PIXFORMAT_JPEG; config.frame_size = FRAMESIZE_QVGA; config.jpeg_quality = 9; config.fb_count = 1; esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); return; } } //continue sending camera frame void liveCam(WiFiClient &client){ //capture a frame camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { Serial.println("Frame buffer could not be acquired"); return; } client.print("--frame\n"); client.print("Content-Type: image/jpeg\n\n"); client.flush(); client.write(fb->buf, fb->len); client.flush(); client.print("\n"); //return the frame buffer back to be reused esp_camera_fb_return(fb); } void setup() { Serial.begin(115200); WiFi.begin("I3.41", "xxx"); Serial.println(""); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); String IP = WiFi.localIP().toString(); Serial.println("IP address: " + IP); index_html.replace("server_ip", IP); server.begin(); configCamera(); } void http_resp(){ WiFiClient client = server.available(); /* check client is connected */ if (client.connected()) { /* client send request? */ /* request end with '\r' -> this is HTTP protocol format */ String req = ""; while(client.available()){ req += (char)client.read(); } Serial.println("request " + req); /* First line of HTTP request is "GET / HTTP/1.1" here "GET /" is a request to get the first page at root "/" "HTTP/1.1" is HTTP version 1.1 */ /* now we parse the request to see which page the client want */ int addr_start = req.indexOf("GET") + strlen("GET"); int addr_end = req.indexOf("HTTP", addr_start); if (addr_start == -1 || addr_end == -1) { Serial.println("Invalid request " + req); return; } req = req.substring(addr_start, addr_end); req.trim(); Serial.println("Request: " + req); client.flush(); String s; /* if request is "/" then client request the first page at root "/" -> we process this by return "Hello world"*/ if (req == "/") { s = "HTTP/1.1 200 OK\n"; s += "Content-Type: text/html\n\n"; s += index_html; s += "\n"; client.print(s); client.stop(); } else if (req == "/video") { live_client = client; live_client.print("HTTP/1.1 200 OK\n"); live_client.print("Content-Type: multipart/x-mixed-replace; boundary=frame\n\n"); live_client.flush(); connected = true; } else { /* if we can not find the page that client request then we return 404 File not found */ s = "HTTP/1.1 404 Not Found\n\n"; client.print(s); client.stop(); } } } void loop() { http_resp(); if(connected == true){ liveCam(live_client); } }
2 Comments