├── README.md └── esp-sdm-mqtt └── esp-sdm-mqtt.ino /README.md: -------------------------------------------------------------------------------- 1 | # ESP8266 MQTT SDM ModBus Master 2 | 3 | Work in progress sketch to read power values via modbus from the well know SDMXXX (SDM120 / SDM220 / SDM630) series power meters from eastron over modbus using an esp8266 and an 3.3V RS485 tranceiver. 4 | 5 | ## Created with 6 | - Arduino 1.8.5 (https://www.arduino.cc/) 7 | - ESP8266 board definition 2.4.1 (https://github.com/esp8266/Arduino) 8 | - SDM_Energy_Meter https://github.com/reaper7/SDM_Energy_Meter 9 | - Tasker (https://github.com/sticilface/Tasker) 10 | - PubSubClient 2.6.0 by Nick O'Leary (https://github.com/knolleary/pubsubclient) 11 | 12 | ### Credits 13 | patrik.mayer@codm.de, 2017 -------------------------------------------------------------------------------- /esp-sdm-mqtt/esp-sdm-mqtt.ino: -------------------------------------------------------------------------------- 1 | /* 2 | esp-sdm-mqtt - patrik.mayer@codm.de 3 | 4 | Work in progress sketch to read power values via modbus from the well know 5 | SDMXXX (SDM120 / SDM220 / SDM630) series power meters from eastron over modbus 6 | using an esp8266 and an 3.3V RS485 tranceiver. 7 | 8 | This uses the SDM library by reaper7 https://github.com/reaper7/SDM_Energy_Meter 9 | mqtt client from https://github.com/knolleary/pubsubclient/ 10 | Tasker from https://github.com/sticilface/Tasker 11 | 12 | Arduino OTA from ESP8266 Arduino Core V2.4 13 | 14 | As this is not finished yet, the documentation will get better by time. 15 | 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | //--------- Configuration 27 | // WiFi 28 | const char* ssid = ""; 29 | const char* password = ""; 30 | 31 | const char* mqttServer = ""; 32 | const char* mqttUser = ""; 33 | const char* mqttPass = ""; 34 | const char* mqttClientName = ""; //will also be used hostname and OTA name 35 | const char* mqttTopicPrefix = ""; 36 | 37 | unsigned long measureDelay = 10000; //read every 60s 38 | 39 | const int rxPin = 4; 40 | const int txPin = 5; 41 | const int derePin = 14; 42 | const long baud = 9600; 43 | 44 | // internal vars 45 | WiFiClient espClient; 46 | PubSubClient mqttClient(espClient); 47 | Tasker tasker; 48 | SDM sdm; 49 | 50 | char mqttTopicStatus[64]; 51 | char mqttTopicIp[64]; 52 | 53 | char mqttTopicVoltage[64]; 54 | char mqttTopicCurrent[64]; 55 | char mqttTopicPower[64]; 56 | char mqttTopicFreq[64]; 57 | 58 | long lastReconnectAttempt = 0; //For the non blocking mqtt reconnect (in millis) 59 | 60 | void setup() { 61 | Serial.begin(115200); //initialize serial 62 | Serial.println("Starting..."); 63 | 64 | sdm.begin(); 65 | 66 | //put in mqtt prefix 67 | sprintf(mqttTopicStatus, "%sstatus", mqttTopicPrefix); 68 | sprintf(mqttTopicIp, "%sip", mqttTopicPrefix); 69 | 70 | sprintf(mqttTopicVoltage, "%svoltage", mqttTopicPrefix); 71 | sprintf(mqttTopicCurrent, "%scurrent", mqttTopicPrefix); 72 | sprintf(mqttTopicPower, "%spower", mqttTopicPrefix); 73 | sprintf(mqttTopicFreq, "%sfreq", mqttTopicPrefix); 74 | 75 | setup_wifi(); 76 | mqttClient.setServer(mqttServer, 1883); 77 | 78 | tasker.setInterval(meassureSDM, measureDelay); 79 | 80 | 81 | //----------- OTA 82 | ArduinoOTA.setHostname(mqttClientName); 83 | 84 | ArduinoOTA.onStart([]() { 85 | String type; 86 | if (ArduinoOTA.getCommand() == U_FLASH) { 87 | type = "sketch"; 88 | } else { // U_SPIFFS 89 | type = "filesystem"; 90 | } 91 | // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() 92 | Serial.println("Start updating " + type); 93 | }); 94 | 95 | ArduinoOTA.onEnd([]() { 96 | Serial.println("\nEnd"); 97 | delay(1000); 98 | ESP.restart(); 99 | }); 100 | 101 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { 102 | Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 103 | }); 104 | 105 | ArduinoOTA.onError([](ota_error_t error) { 106 | Serial.printf("Error[%u]: ", error); 107 | if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); 108 | else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); 109 | else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); 110 | else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); 111 | else if (error == OTA_END_ERROR) Serial.println("End Failed"); 112 | }); 113 | ArduinoOTA.begin(); 114 | 115 | } 116 | 117 | void loop() { 118 | 119 | //handle mqtt connection, non-blocking 120 | if (!mqttClient.connected()) { 121 | long now = millis(); 122 | if (now - lastReconnectAttempt > 5000) { 123 | lastReconnectAttempt = now; 124 | // Attempt to reconnect 125 | if (MqttReconnect()) { 126 | lastReconnectAttempt = 0; 127 | } 128 | } 129 | } 130 | mqttClient.loop(); 131 | 132 | tasker.loop(); 133 | 134 | //handle OTA 135 | ArduinoOTA.handle(); 136 | 137 | } 138 | 139 | void meassureSDM(int) { 140 | 141 | float v = sdm.readVal(SDM220T_VOLTAGE); //read voltage 142 | float c = sdm.readVal(SDM220T_CURRENT); //read curren 143 | float p = sdm.readVal(SDM220T_POWER); //read power 144 | float f = sdm.readVal(SDM220T_FREQUENCY); //read frequency 145 | 146 | if (v != NAN) { 147 | mqttClient.publish(mqttTopicVoltage, String(v, 2).c_str(), true); 148 | } 149 | 150 | if (c != NAN) { 151 | mqttClient.publish(mqttTopicCurrent, String(c, 2).c_str(), true); 152 | } 153 | 154 | if (p != NAN) { 155 | mqttClient.publish(mqttTopicPower, String(p, 2).c_str(), true); 156 | } 157 | 158 | if (f != NAN) { 159 | mqttClient.publish(mqttTopicFreq, String(f, 2).c_str(), true); 160 | } 161 | 162 | Serial.printf("\nVoltage: %sV\nCurrent: %sA\nPower: %sW\nFrequency: %sHz\n", String(v, 2).c_str(), String(c, 2).c_str(), String(p, 2).c_str(), String(f, 2).c_str()); 163 | Serial.println(); 164 | 165 | } 166 | 167 | void setup_wifi() { 168 | 169 | delay(10); 170 | 171 | Serial.println(); 172 | Serial.print("Connecting to "); 173 | Serial.println(ssid); 174 | 175 | WiFi.mode(WIFI_STA); //disable AP mode, only station 176 | WiFi.hostname(mqttClientName); 177 | WiFi.begin(ssid, password); 178 | 179 | while (WiFi.status() != WL_CONNECTED) { 180 | delay(500); 181 | Serial.print("."); 182 | } 183 | 184 | Serial.println(""); 185 | Serial.println("WiFi connected"); 186 | Serial.println("IP address: "); 187 | Serial.println(WiFi.localIP()); 188 | } 189 | 190 | 191 | bool MqttReconnect() { 192 | 193 | if (!mqttClient.connected()) { 194 | 195 | Serial.print("Attempting MQTT connection..."); 196 | 197 | // Attempt to connect with last will retained 198 | if (mqttClient.connect(mqttClientName, mqttUser, mqttPass, mqttTopicStatus, 1, true, "offline")) { 199 | 200 | Serial.println("connected"); 201 | 202 | // Once connected, publish an announcement... 203 | char curIp[16]; 204 | sprintf(curIp, "%d.%d.%d.%d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]); 205 | 206 | mqttClient.publish(mqttTopicStatus, "online", true); 207 | mqttClient.publish(mqttTopicIp, curIp, true); 208 | 209 | } else { 210 | Serial.print("failed, rc="); 211 | Serial.print(mqttClient.state()); 212 | Serial.println(" try again in 5 seconds"); 213 | } 214 | } 215 | return mqttClient.connected(); 216 | } 217 | --------------------------------------------------------------------------------