├── README.md ├── sdm ├── SDM_Config_User.h ├── sdm_esphome.h └── SDM.h ├── Example NodeMcu ESP8266 └── Example ESP32 wrover /README.md: -------------------------------------------------------------------------------- 1 | # ESPHome+SDM630 2 | 3 | # 1. About 4 | This repository is an instruction how to use energy meter SDM630 Modbus V2 with ESP32/8266 loaded with ESPHome. Program is meant to read all needed data from the counter if you need something more feel free to modify the code. 5 | 6 | # 2. Needed things to start 7 | 8 | 1. SDM630 Modbus V2 can be bought from Aliexpress example link below: 9 | https://pl.aliexpress.com/item/32755125115.html?spm=a2g0s.9042311.0.0.7f515c0fyqdQLy 10 | 2. Modbus konwerter from RS485 to UART 11 | https://pl.aliexpress.com/item/1005001346792286.html?spm=a2g0o.productlist.0.0.379b6239Khooh1&algo_pvid=null&algo_expid=null&btsid=2100bdcf16209689305085851eb468&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_ 12 | 3. ESP board can be ESP8266 or ESP32 13 | 4. Home Assistant with ESPHome addon installed 14 | 15 | # 3. Connection diagram 16 | Wemos D1 ESP32 17 | ![image](https://user-images.githubusercontent.com/61471407/118225712-e88ae980-b485-11eb-9c2b-428857e21f10.png) 18 | 19 | Wemos D1 ESP8266 20 | ![image](https://user-images.githubusercontent.com/61471407/118225594-b24d6a00-b485-11eb-94c8-515687f81e91.png) 21 | 22 | Usually any board which is compatible with ESPHome should work. Only connect TX port of ESP to TX of converter, RX to RX, A+ from converter to A+ of SDM630, B- to B- and G to G. 23 | 24 | # 4. Programming 25 | 1. Download folder SDM and paste it into below location of your Home Assistant server 26 | \\\your_Home_Assistant_address\config\esphome\custom_components 27 | If folder custom_components doesn't exist create it. 28 | 2. Create New node according to your board type. Paste example code to your node and modify it according to your code and configuration!! 29 | 3. Validate code, compile and upload it. 30 | 4. Rememmber that RS converter and SDM630 need to be connected and powered on, otherwise in logs you will see nothing and ESP board will be resetting and unavailable. So the best way to test is the code working, connect ing SDM630 normal cable with plug to wall socket and make connection according to diagram in point 3 31 | 5. If we have brand new ESP it is necessary to download Firmware generated in ESPHome and upload it with below tool: 32 | https://github.com/esphome/esphome-flasher/releases/tag/v1.3.0 33 | -------------------------------------------------------------------------------- /sdm/SDM_Config_User.h: -------------------------------------------------------------------------------- 1 | /* Library for reading SDM 72/120/220/230/630 Modbus Energy meters. 2 | * Reading via Hardware or Software Serial library & rs232<->rs485 converter 3 | * 2016-2019 Reaper7 (tested on wemos d1 mini->ESP8266 with Arduino 1.8.10 & 2.5.2 esp8266 core) 4 | * crc calculation by Jaime García (https://github.com/peninquen/Modbus-Energy-Monitor-Arduino/) 5 | */ 6 | 7 | /* 8 | * USER CONFIG: 9 | */ 10 | 11 | //------------------------------------------------------------------------------ 12 | 13 | /* 14 | * define or undefine USE_HARDWARESERIAL (uncomment only one or none) 15 | */ 16 | //#undef USE_HARDWARESERIAL 17 | #define USE_HARDWARESERIAL 18 | 19 | //------------------------------------------------------------------------------ 20 | 21 | /* 22 | * define user baudrate 23 | */ 24 | //#define SDM_UART_BAUD 9600 25 | 26 | //------------------------------------------------------------------------------ 27 | 28 | /* 29 | * define user SDM_RX_PIN and SDM_TX_PIN for esp/avr Software Serial option 30 | * or ESP32 with Hardware Serial if default core pins are not suitable 31 | */ 32 | #if defined ( USE_HARDWARESERIAL ) 33 | #if defined ( ESP32 ) 34 | #define SDM_RX_PIN 13 35 | #define SDM_TX_PIN 15 36 | #endif 37 | #else 38 | #if defined ( ESP8266 ) || defined ( ESP32 ) 39 | #define SDM_RX_PIN 13 40 | #define SDM_TX_PIN 15 41 | #else 42 | #define SDM_RX_PIN 10 43 | #define SDM_TX_PIN 11 44 | #endif 45 | #endif 46 | 47 | //------------------------------------------------------------------------------ 48 | 49 | /* 50 | * define user DERE_PIN for control MAX485 DE/RE lines (connect DE & /RE together to this pin) 51 | */ 52 | //#define DERE_PIN NOT_A_PIN 53 | 54 | //------------------------------------------------------------------------------ 55 | 56 | #if defined ( USE_HARDWARESERIAL ) 57 | 58 | /* 59 | * define user SDM_UART_CONFIG for hardware serial 60 | */ 61 | //#define SDM_UART_CONFIG SERIAL_8N1 62 | 63 | //---------------------------------------------------------------------------- 64 | 65 | /* 66 | * define user SWAPHWSERIAL, if true(1) then swap uart pins from 3/1 to 13/15 (only ESP8266) 67 | */ 68 | //#define SWAPHWSERIAL 0 69 | 70 | #else 71 | 72 | /* 73 | * define user SDM_UART_CONFIG for software serial 74 | */ 75 | //#define SDM_UART_CONFIG SWSERIAL_8N1 76 | 77 | #endif 78 | 79 | //------------------------------------------------------------------------------ 80 | 81 | /* 82 | * define user MAX_MILLIS_TO_WAIT to wait for response from SDM 83 | */ 84 | //#define MAX_MILLIS_TO_WAIT 500 85 | 86 | //------------------------------------------------------------------------------ -------------------------------------------------------------------------------- /Example NodeMcu ESP8266: -------------------------------------------------------------------------------- 1 | substitutions: 2 | devicename: test 3 | friendly_name: node_test 4 | ip_address: !secret test 5 | 6 | esphome: 7 | name: $devicename 8 | platform: ESP8266 9 | board: nodemcuv2 10 | includes: 11 | - custom_components/sdm/SDM_Config_User.h 12 | - custom_components/sdm/SDM.h 13 | - custom_components/sdm/sdm_esphome.h 14 | 15 | 16 | wifi: 17 | ssid: !secret wifi_id 18 | password: !secret wifi_pwd 19 | manual_ip: 20 | static_ip: ${ip_address} 21 | gateway: 192.168.0.1 22 | subnet: 255.255.255.0 23 | 24 | # Enable fallback hotspot (captive portal) in case wifi connection fails 25 | 26 | # Enable logging 27 | logger: 28 | level: DEBUG 29 | baud_rate: 0 30 | # level: VERY_VERBOSE 31 | esp8266_store_log_strings_in_flash: False 32 | 33 | # Enable Home Assistant API 34 | api: 35 | 36 | ota: 37 | 38 | # Enable Home Assistant API 39 | 40 | time: 41 | - platform: homeassistant 42 | id: homeassistant_time 43 | 44 | 45 | uart: 46 | tx_pin: TX 47 | rx_pin: RX 48 | baud_rate: 9600 49 | stop_bits: 1 50 | 51 | binary_sensor: 52 | # https://esphome.io/components/binary_sensor/status.html 53 | - platform: status 54 | name: "SDM630 Status" 55 | 56 | sensor: 57 | - platform: uptime 58 | name: "SDM630 Uptime Sensor" 59 | 60 | - platform: custom 61 | lambda: |- 62 | auto sdm_sensors = new SDMComponent(); 63 | App.register_component(sdm_sensors); 64 | return {sdm_sensors->voltage_sensor_1,sdm_sensors->voltage_sensor_2,sdm_sensors->voltage_sensor_3, sdm_sensors->current_sensor_1,sdm_sensors->current_sensor_2,sdm_sensors->current_sensor_3,sdm_sensors->power_sensor_1,sdm_sensors->power_sensor_2,sdm_sensors->power_sensor_3,sdm_sensors->vars_sensor_1,sdm_sensors->vars_sensor_2,sdm_sensors->vars_sensor_3, sdm_sensors->frequency_sensor,sdm_sensors->active_energy_import_sensor,sdm_sensors->active_energy_export_sensor,sdm_sensors->reactive_energy_import_sensor,sdm_sensors->reactive_energy_export_sensor,sdm_sensors->import_kwh_sensor_1,sdm_sensors->import_kwh_sensor_2,sdm_sensors->import_kwh_sensor_3,sdm_sensors->export_kwh_sensor_1,sdm_sensors->export_kwh_sensor_2,sdm_sensors->export_kwh_sensor_3,sdm_sensors->power_factor_sensor_1,sdm_sensors->power_factor_sensor_2,sdm_sensors->power_factor_sensor_3,sdm_sensors->energy_total_sensor_1,sdm_sensors->energy_total_sensor_2,sdm_sensors->energy_total_sensor_3}; 65 | sensors: 66 | - name: "Voltage Phase 1" 67 | unit_of_measurement: V 68 | accuracy_decimals: 1 69 | - name: "Voltage Phase 2" 70 | unit_of_measurement: V 71 | accuracy_decimals: 1 72 | - name: "Voltage Phase 3" 73 | unit_of_measurement: V 74 | accuracy_decimals: 1 75 | 76 | - name: "Current Phase 1" 77 | unit_of_measurement: A 78 | accuracy_decimals: 2 79 | - name: "Current Phase 2" 80 | unit_of_measurement: A 81 | accuracy_decimals: 2 82 | - name: "Current Phase 3" 83 | unit_of_measurement: A 84 | accuracy_decimals: 2 85 | 86 | - name: "Power Phase 1" 87 | unit_of_measurement: W 88 | accuracy_decimals: 2 89 | id: power_1 90 | - name: "Power Phase 2" 91 | unit_of_measurement: W 92 | accuracy_decimals: 2 93 | id: power_2 94 | - name: "Power Phase 3" 95 | unit_of_measurement: W 96 | accuracy_decimals: 2 97 | id: power_3 98 | 99 | - name: "VArs Phase 1" 100 | unit_of_measurement: VAr 101 | accuracy_decimals: 2 102 | - name: "VArs Phase 2" 103 | unit_of_measurement: VAr 104 | accuracy_decimals: 2 105 | - name: "VArs Phase 3" 106 | unit_of_measurement: VAr 107 | accuracy_decimals: 2 108 | 109 | - name: "Frequency" 110 | unit_of_measurement: Hz 111 | accuracy_decimals: 1 112 | 113 | - name: "Active Energy Import" 114 | unit_of_measurement: Wh 115 | accuracy_decimals: 2 116 | - name: "Active Energy Export" 117 | unit_of_measurement: Wh 118 | accuracy_decimals: 2 119 | - name: "Reactive Energy Import" 120 | unit_of_measurement: VARh 121 | accuracy_decimals: 2 122 | - name: "Reactive Energy Export" 123 | unit_of_measurement: VARh 124 | accuracy_decimals: 2 125 | 126 | - name: "Import Phase 1" 127 | unit_of_measurement: kWh 128 | accuracy_decimals: 2 129 | - name: "Import Phase 2" 130 | unit_of_measurement: kWh 131 | accuracy_decimals: 2 132 | - name: "Import Phase 3" 133 | unit_of_measurement: kWh 134 | accuracy_decimals: 2 135 | 136 | - name: "Export Phase 1" 137 | unit_of_measurement: kWh 138 | accuracy_decimals: 2 139 | - name: "Export Phase 2" 140 | unit_of_measurement: kWh 141 | accuracy_decimals: 2 142 | - name: "Export Phase 3" 143 | unit_of_measurement: kWh 144 | accuracy_decimals: 2 145 | 146 | - name: "Power Factor Phase 1" 147 | accuracy_decimals: 2 148 | - name: "Power Factor Phase 2" 149 | accuracy_decimals: 2 150 | - name: "Power Factor Phase 3" 151 | accuracy_decimals: 2 152 | 153 | - name: "Energy Total Phase 1" 154 | unit_of_measurement: kWh 155 | accuracy_decimals: 2 156 | - name: "Energy Total Phase 2" 157 | unit_of_measurement: kWh 158 | accuracy_decimals: 2 159 | - name: "Energy Total Phase 3" 160 | unit_of_measurement: kWh 161 | accuracy_decimals: 2 162 | #tu gdzies jest blad 163 | - platform: total_daily_energy 164 | name: "Daily Energy Phase 1" 165 | icon: "mdi:counter" 166 | power_id: power_1 167 | filters: 168 | # Multiplication factor from W to kW is 0.001 169 | - multiply: 0.001 170 | unit_of_measurement: kWh 171 | - platform: total_daily_energy 172 | name: "Daily Energy Phase 2" 173 | icon: "mdi:counter" 174 | power_id: power_2 175 | filters: 176 | # Multiplication factor from W to kW is 0.001 177 | - multiply: 0.001 178 | unit_of_measurement: kWh 179 | - platform: total_daily_energy 180 | name: "Daily Energy Phase 3" 181 | icon: "mdi:counter" 182 | power_id: power_3 183 | filters: 184 | # Multiplication factor from W to kW is 0.001 185 | - multiply: 0.001 186 | unit_of_measurement: kWh 187 | -------------------------------------------------------------------------------- /sdm/sdm_esphome.h: -------------------------------------------------------------------------------- 1 | #include "esphome.h" 2 | 3 | class SDMComponent : public PollingComponent { 4 | public: 5 | SDM sdm = SDM(Serial, 9600, NOT_A_PIN, SERIAL_8N1, false); 6 | /*Voltage*/ 7 | Sensor *voltage_sensor_1 = new Sensor(); 8 | Sensor *voltage_sensor_2 = new Sensor(); 9 | Sensor *voltage_sensor_3 = new Sensor(); 10 | /*Current*/ 11 | Sensor *current_sensor_1 = new Sensor(); 12 | Sensor *current_sensor_2 = new Sensor(); 13 | Sensor *current_sensor_3 = new Sensor(); 14 | Sensor *currentsum_sensor = new Sensor(); 15 | //Power 16 | Sensor *power_sensor_1 = new Sensor(); 17 | Sensor *power_sensor_2 = new Sensor(); 18 | Sensor *power_sensor_3 = new Sensor(); 19 | Sensor *powersum_sensor = new Sensor(); 20 | //Vars 21 | Sensor *vars_sensor_1 = new Sensor(); 22 | Sensor *vars_sensor_2 = new Sensor(); 23 | Sensor *vars_sensor_3 = new Sensor(); 24 | Sensor *varssum_sensor = new Sensor(); 25 | //frequency 26 | Sensor *frequency_sensor = new Sensor(); 27 | //import export energy 28 | Sensor *active_energy_import_sensor = new Sensor(); 29 | Sensor *active_energy_export_sensor = new Sensor(); 30 | Sensor *reactive_energy_import_sensor = new Sensor(); 31 | Sensor *reactive_energy_export_sensor = new Sensor(); 32 | Sensor *import_kwh_sensor_1 = new Sensor(); 33 | Sensor *import_kwh_sensor_2 = new Sensor(); 34 | Sensor *import_kwh_sensor_3 = new Sensor(); 35 | Sensor *importsum_kwh_sensor = new Sensor(); 36 | Sensor *export_kwh_sensor_1 = new Sensor(); 37 | Sensor *export_kwh_sensor_2 = new Sensor(); 38 | Sensor *export_kwh_sensor_3 = new Sensor(); 39 | Sensor *exportsum_kwh_sensor = new Sensor(); 40 | //power factor 41 | Sensor *power_factor_sensor_1 = new Sensor(); 42 | Sensor *power_factor_sensor_2 = new Sensor(); 43 | Sensor *power_factor_sensor_3 = new Sensor(); 44 | Sensor *power_factor_total_sensor = new Sensor(); 45 | //Energy kWh 46 | Sensor *energy_total_sensor_1 = new Sensor(); 47 | Sensor *energy_total_sensor_2 = new Sensor(); 48 | Sensor *energy_total_sensor_3 = new Sensor(); 49 | Sensor *energy_totalsum_sensor = new Sensor(); 50 | 51 | SDMComponent() : PollingComponent(15000) {} 52 | 53 | void setup() override { 54 | ESP_LOGD("SDM", "Setup completed"); 55 | } 56 | 57 | void update() override { 58 | // ESP_LOGD("SDM", "Start reading"); 59 | float voltage1 = sdm.readVal(SDM630_VOLTAGE1); 60 | float voltage2 = sdm.readVal(SDM630_VOLTAGE2); 61 | float voltage3 = sdm.readVal(SDM630_VOLTAGE3); 62 | // ESP_LOGD("SDM", "Voltages %f %f %f", voltage1, voltage2, voltage3); 63 | voltage_sensor_1->publish_state(voltage1); 64 | voltage_sensor_2->publish_state(voltage2); 65 | voltage_sensor_3->publish_state(voltage3); 66 | 67 | float current1 = sdm.readVal(SDM630_CURRENT1); 68 | float current2 = sdm.readVal(SDM630_CURRENT2); 69 | float current3 = sdm.readVal(SDM630_CURRENT3); 70 | float currentsum = sdm.readVal(SDM630_CURRENTSUM); 71 | current_sensor_1->publish_state(current1); 72 | current_sensor_2->publish_state(current2); 73 | current_sensor_3->publish_state(current3); 74 | currentsum_sensor->publish_state(currentsum); 75 | 76 | float power1 = sdm.readVal(SDM630_POWER1); 77 | float power2 = sdm.readVal(SDM630_POWER2); 78 | float power3 = sdm.readVal(SDM630_POWER3); 79 | float powersum = sdm.readVal(SDM630_POWERTOTAL); 80 | power_sensor_1->publish_state(power1); 81 | power_sensor_2->publish_state(power2); 82 | power_sensor_3->publish_state(power3); 83 | powersum_sensor->publish_state(powersum); 84 | 85 | float vars1 = sdm.readVal(SDM630_VOLT_AMPS_REACTIVE1); 86 | float vars2 = sdm.readVal(SDM630_VOLT_AMPS_REACTIVE2); 87 | float vars3 = sdm.readVal(SDM630_VOLT_AMPS_REACTIVE3); 88 | float varssum = sdm.readVal(SDM630_VOLT_AMPS_REACTIVE_TOTAL); 89 | vars_sensor_1->publish_state(vars1); 90 | vars_sensor_2->publish_state(vars2); 91 | vars_sensor_3->publish_state(vars3); 92 | varssum_sensor->publish_state(varssum); 93 | 94 | float import1 = sdm.readVal(SDM630_IMPORT1); 95 | float import2 = sdm.readVal(SDM630_IMPORT2); 96 | float import3 = sdm.readVal(SDM630_IMPORT3); 97 | // ESP_LOGD("SDM", "Imports %f %f %f", import1, import2, import3); 98 | import_kwh_sensor_1->publish_state(import1); 99 | import_kwh_sensor_2->publish_state(import2); 100 | import_kwh_sensor_3->publish_state(import3); 101 | importsum_kwh_sensor->publish_state(import1 + import2 + import3); 102 | 103 | float export1 = sdm.readVal(SDM630_EXPORT1); 104 | float export2 = sdm.readVal(SDM630_EXPORT2); 105 | float export3 = sdm.readVal(SDM630_EXPORT3); 106 | // ESP_LOGD("SDM", "Exports %f %f %f", export1, export2, export3); 107 | export_kwh_sensor_1->publish_state(export1); 108 | export_kwh_sensor_2->publish_state(export2); 109 | export_kwh_sensor_3->publish_state(export3); 110 | exportsum_kwh_sensor->publish_state(export1 + export2 + export3); 111 | 112 | float frequency = sdm.readVal(SDM630_FREQUENCY); 113 | frequency_sensor->publish_state(frequency); 114 | 115 | float active_ene_import = sdm.readVal(SDM630_IMPORT_ACTIVE_ENERGY); 116 | float active_ene_export = sdm.readVal(SDM630_EXPORT_ACTIVE_ENERGY); 117 | float reactive_ene_import = sdm.readVal(SDM630_IMPORT_REACTIVE_ENERGY); 118 | float reactive_ene_export = sdm.readVal(SDM630_EXPORT_REACTIVE_ENERGY); 119 | active_energy_import_sensor->publish_state(active_ene_import); 120 | active_energy_export_sensor->publish_state(active_ene_export); 121 | reactive_energy_import_sensor->publish_state(reactive_ene_import); 122 | reactive_energy_export_sensor->publish_state(reactive_ene_export); 123 | 124 | float power_factor1 = sdm.readVal(SDM630_POWER_FACTOR1); 125 | float power_factor2 = sdm.readVal(SDM630_POWER_FACTOR2); 126 | float power_factor3 = sdm.readVal(SDM630_POWER_FACTOR3); 127 | float power_factor_total = sdm.readVal(SDM630_POWER_FACTOR_TOTAL); 128 | power_factor_sensor_1->publish_state(power_factor1); 129 | power_factor_sensor_2->publish_state(power_factor2); 130 | power_factor_sensor_3->publish_state(power_factor3); 131 | power_factor_total_sensor->publish_state(power_factor_total); 132 | 133 | float ene_total1 = sdm.readVal(SDM630_TOTAL_ENERGY1); 134 | float ene_total2 = sdm.readVal(SDM630_TOTAL_ENERGY2); 135 | float ene_total3 = sdm.readVal(SDM630_TOTAL_ENERGY3); 136 | //ESP_LOGD("SDM", "Energy totals %f %f %f", ene_total1, ene_total1, ene_total1); 137 | energy_total_sensor_1->publish_state(ene_total1); 138 | energy_total_sensor_2->publish_state(ene_total2); 139 | energy_total_sensor_3->publish_state(ene_total3); 140 | energy_totalsum_sensor->publish_state(ene_total1 + ene_total2 + ene_total3); 141 | 142 | // ESP_LOGD("SDM", "End reading"); 143 | } 144 | }; 145 | -------------------------------------------------------------------------------- /Example ESP32 wrover: -------------------------------------------------------------------------------- 1 | substitutions: 2 | devicename: sdm630 3 | friendly_name: ttgo_sdm630 4 | ip_address: !secret sdm630 5 | 6 | esphome: 7 | name: $devicename 8 | platform: ESP32 9 | board: esp-wrover-kit 10 | includes: 11 | - custom_components/sdm/SDM_Config_User.h 12 | - custom_components/sdm/SDM.h 13 | - custom_components/sdm/sdm_esphome.h 14 | 15 | wifi: 16 | ssid: !secret wifi_id 17 | password: !secret wifi_pwd 18 | manual_ip: 19 | static_ip: ${ip_address} 20 | gateway: 192.168.0.1 21 | subnet: 255.255.255.0 22 | 23 | # Enable fallback hotspot (captive portal) in case wifi connection fails 24 | #ap: 25 | # ssid: "Home Lights Notify" 26 | #password: "YiwdlGqxsCgP" 27 | 28 | #captive_portal: 29 | 30 | # Enable logging 31 | logger: 32 | level: DEBUG 33 | baud_rate: 0 34 | 35 | # Enable Home Assistant API 36 | api: 37 | 38 | uart: 39 | - id: modbus_uart 40 | tx_pin: TX 41 | rx_pin: RX 42 | baud_rate: 9600 43 | stop_bits: 1 44 | 45 | ota: 46 | 47 | time: 48 | - platform: homeassistant 49 | id: homeassistant_time 50 | 51 | binary_sensor: 52 | # https://esphome.io/components/binary_sensor/status.html 53 | - platform: status 54 | name: "SDM630 Status" 55 | 56 | sensor: 57 | - platform: uptime 58 | name: "SDM630 Uptime Sensor" 59 | 60 | - platform: custom 61 | lambda: |- 62 | auto sdm_sensors = new SDMComponent(); 63 | App.register_component(sdm_sensors); 64 | return {sdm_sensors->voltage_sensor_1,sdm_sensors->voltage_sensor_2,sdm_sensors->voltage_sensor_3, sdm_sensors->current_sensor_1,sdm_sensors->current_sensor_2,sdm_sensors->current_sensor_3,sdm_sensors->currentsum_sensor, sdm_sensors->power_sensor_1,sdm_sensors->power_sensor_2,sdm_sensors->power_sensor_3,sdm_sensors->powersum_sensor,sdm_sensors->vars_sensor_1,sdm_sensors->vars_sensor_2,sdm_sensors->vars_sensor_3,sdm_sensors->varssum_sensor, sdm_sensors->frequency_sensor,sdm_sensors->active_energy_import_sensor,sdm_sensors->active_energy_export_sensor,sdm_sensors->reactive_energy_import_sensor,sdm_sensors->reactive_energy_export_sensor,sdm_sensors->import_kwh_sensor_1,sdm_sensors->import_kwh_sensor_2,sdm_sensors->import_kwh_sensor_3,sdm_sensors->importsum_kwh_sensor,sdm_sensors->export_kwh_sensor_1,sdm_sensors->export_kwh_sensor_2,sdm_sensors->export_kwh_sensor_3,sdm_sensors->exportsum_kwh_sensor,sdm_sensors->power_factor_sensor_1,sdm_sensors->power_factor_sensor_2,sdm_sensors->power_factor_sensor_3,sdm_sensors->power_factor_total_sensor,sdm_sensors->energy_total_sensor_1,sdm_sensors->energy_total_sensor_2,sdm_sensors->energy_total_sensor_3,sdm_sensors->energy_totalsum_sensor}; 65 | sensors: 66 | - name: "Voltage Phase 1" 67 | unit_of_measurement: V 68 | accuracy_decimals: 1 69 | - name: "Voltage Phase 2" 70 | unit_of_measurement: V 71 | accuracy_decimals: 1 72 | - name: "Voltage Phase 3" 73 | unit_of_measurement: V 74 | accuracy_decimals: 1 75 | 76 | - name: "Current Phase 1" 77 | unit_of_measurement: A 78 | accuracy_decimals: 2 79 | - name: "Current Phase 2" 80 | unit_of_measurement: A 81 | accuracy_decimals: 2 82 | - name: "Current Phase 3" 83 | unit_of_measurement: A 84 | accuracy_decimals: 2 85 | - name: "Current Sum" 86 | unit_of_measurement: A 87 | accuracy_decimals: 2 88 | 89 | - name: "Power Phase 1" 90 | unit_of_measurement: W 91 | accuracy_decimals: 2 92 | id: power_1 93 | - name: "Power Phase 2" 94 | unit_of_measurement: W 95 | accuracy_decimals: 2 96 | id: power_2 97 | - name: "Power Phase 3" 98 | unit_of_measurement: W 99 | accuracy_decimals: 2 100 | id: power_3 101 | - name: "Power Sum" 102 | unit_of_measurement: W 103 | accuracy_decimals: 2 104 | id: power_sum 105 | 106 | - name: "VArs Phase 1" 107 | unit_of_measurement: VAr 108 | accuracy_decimals: 2 109 | - name: "VArs Phase 2" 110 | unit_of_measurement: VAr 111 | accuracy_decimals: 2 112 | - name: "VArs Phase 3" 113 | unit_of_measurement: VAr 114 | accuracy_decimals: 2 115 | - name: "VArs Sum" 116 | unit_of_measurement: VAr 117 | accuracy_decimals: 2 118 | 119 | - name: "Frequency" 120 | unit_of_measurement: Hz 121 | accuracy_decimals: 1 122 | 123 | - name: "Active Energy Import" 124 | unit_of_measurement: Wh 125 | accuracy_decimals: 2 126 | - name: "Active Energy Export" 127 | unit_of_measurement: Wh 128 | accuracy_decimals: 2 129 | - name: "Reactive Energy Import" 130 | unit_of_measurement: VARh 131 | accuracy_decimals: 2 132 | - name: "Reactive Energy Export" 133 | unit_of_measurement: VARh 134 | accuracy_decimals: 2 135 | 136 | - name: "Import Phase 1" 137 | unit_of_measurement: kWh 138 | accuracy_decimals: 2 139 | - name: "Import Phase 2" 140 | unit_of_measurement: kWh 141 | accuracy_decimals: 2 142 | - name: "Import Phase 3" 143 | unit_of_measurement: kWh 144 | accuracy_decimals: 2 145 | - name: "Import Sum" 146 | unit_of_measurement: kWh 147 | accuracy_decimals: 2 148 | 149 | - name: "Export Phase 1" 150 | unit_of_measurement: kWh 151 | accuracy_decimals: 2 152 | - name: "Export Phase 2" 153 | unit_of_measurement: kWh 154 | accuracy_decimals: 2 155 | - name: "Export Phase 3" 156 | unit_of_measurement: kWh 157 | accuracy_decimals: 2 158 | - name: "Export Sum" 159 | unit_of_measurement: kWh 160 | accuracy_decimals: 2 161 | 162 | - name: "Power Factor Phase 1" 163 | accuracy_decimals: 2 164 | - name: "Power Factor Phase 2" 165 | accuracy_decimals: 2 166 | - name: "Power Factor Phase 3" 167 | accuracy_decimals: 2 168 | - name: "Power Factor Sum" 169 | accuracy_decimals: 2 170 | 171 | - name: "Energy Total Phase 1" 172 | unit_of_measurement: kWh 173 | accuracy_decimals: 2 174 | - name: "Energy Total Phase 2" 175 | unit_of_measurement: kWh 176 | accuracy_decimals: 2 177 | - name: "Energy Total Phase 3" 178 | unit_of_measurement: kWh 179 | accuracy_decimals: 2 180 | - name: "Energy Total Sum" 181 | unit_of_measurement: kWh 182 | accuracy_decimals: 2 183 | 184 | #Auto create daily total energy counter for each Phase 185 | - platform: total_daily_energy 186 | name: "Daily Energy Phase 1" 187 | icon: "mdi:counter" 188 | power_id: power_1 189 | filters: 190 | # Multiplication factor from W to kW is 0.001 191 | - multiply: 0.001 192 | unit_of_measurement: kWh 193 | - platform: total_daily_energy 194 | name: "Daily Energy Phase 2" 195 | icon: "mdi:counter" 196 | power_id: power_2 197 | filters: 198 | # Multiplication factor from W to kW is 0.001 199 | - multiply: 0.001 200 | unit_of_measurement: kWh 201 | - platform: total_daily_energy 202 | name: "Daily Energy Phase 3" 203 | icon: "mdi:counter" 204 | power_id: power_3 205 | filters: 206 | # Multiplication factor from W to kW is 0.001 207 | - multiply: 0.001 208 | unit_of_measurement: kWh 209 | - platform: total_daily_energy 210 | name: "Daily Energy Sum" 211 | icon: "mdi:counter" 212 | power_id: power_sum 213 | filters: 214 | # Multiplication factor from W to kW is 0.001 215 | - multiply: 0.001 216 | unit_of_measurement: kWh 217 | -------------------------------------------------------------------------------- /sdm/SDM.h: -------------------------------------------------------------------------------- 1 | /* Library for reading SDM 72/120/220/230/630 Modbus Energy meters. 2 | * Reading via Hardware or Software Serial library & rs232<->rs485 converter 3 | * 2016-2019 Reaper7 (tested on wemos d1 mini->ESP8266 with Arduino 1.8.10 & 2.5.2 esp8266 core) 4 | * crc calculation by Jaime García (https://github.com/peninquen/Modbus-Energy-Monitor-Arduino/) 5 | */ 6 | //------------------------------------------------------------------------------ 7 | #ifndef SDM_h 8 | #define SDM_h 9 | #define USE_HARDWARESERIAL 10 | //------------------------------------------------------------------------------ 11 | #include 12 | #include 13 | #if defined ( USE_HARDWARESERIAL ) 14 | #include 15 | #else 16 | #include 17 | #endif 18 | //------------------------------------------------------------------------------ 19 | //DEFAULT CONFIG (DO NOT CHANGE ANYTHING!!! for changes use SDM_Config_User.h): 20 | //------------------------------------------------------------------------------ 21 | #if !defined ( SDM_UART_BAUD ) 22 | #define SDM_UART_BAUD 4800 //default baudrate 23 | #endif 24 | 25 | #if !defined ( DERE_PIN ) 26 | #define DERE_PIN NOT_A_PIN //default digital pin for control MAX485 DE/RE lines (connect DE & /RE together to this pin) 27 | #endif 28 | 29 | #if defined ( USE_HARDWARESERIAL ) 30 | 31 | #if !defined ( SDM_UART_CONFIG ) 32 | #define SDM_UART_CONFIG SERIAL_8N1 //default hardware uart config 33 | #endif 34 | 35 | #if defined ( ESP8266 ) && !defined ( SWAPHWSERIAL ) 36 | #define SWAPHWSERIAL 0 //(only esp8266) when hwserial used, then swap uart pins from 3/1 to 13/15 (default not swap) 37 | #endif 38 | 39 | #if defined ( ESP32 ) 40 | #if !defined ( SDM_RX_PIN ) 41 | #define SDM_RX_PIN -1 //use default rx pin for selected port 42 | #endif 43 | #if !defined ( SDM_TX_PIN ) 44 | #define SDM_TX_PIN -1 //use default tx pin for selected port 45 | #endif 46 | #endif 47 | 48 | #else 49 | 50 | #if defined ( ESP8266 ) || defined ( ESP32 ) 51 | #if !defined ( SDM_UART_CONFIG ) 52 | #define SDM_UART_CONFIG SWSERIAL_8N1 //default softwareware uart config for esp8266/esp32 53 | #endif 54 | #endif 55 | 56 | // #if !defined ( SDM_RX_PIN ) || !defined ( SDM_TX_PIN ) 57 | // #error "SDM_RX_PIN and SDM_TX_PIN must be defined in SDM_Config_User.h for Software Serial option)" 58 | // #endif 59 | 60 | #if !defined ( SDM_RX_PIN ) 61 | #define SDM_RX_PIN -1 62 | #endif 63 | #if !defined ( SDM_TX_PIN ) 64 | #define SDM_TX_PIN -1 65 | #endif 66 | 67 | #endif 68 | 69 | #if !defined ( MAX_MILLIS_TO_WAIT ) 70 | #define MAX_MILLIS_TO_WAIT 500 //default max time to wait for response from SDM 71 | #endif 72 | //------------------------------------------------------------------------------ 73 | #define FRAMESIZE 9 //size of out/in array 74 | #define SDM_REPLY_BYTE_COUNT 0x04 //number of bytes with data 75 | 76 | #define SDM_B_01 0x01 //BYTE 1 -> slave address (default value 1 read from node 1) 77 | #define SDM_B_02 0x04 //BYTE 2 -> function code (default value 0x04 read from 3X input registers) 78 | //BYTES 3 & 4 (BELOW) 79 | //SDM 72 registers 80 | #define SDM72_TOTAL_POWER 0x0034 //W 81 | #define SDM72_IMPORT_ENERGY 0x0048 //kWh 82 | #define SDM72_EXPORT_ENERGY 0x004A //kWh 83 | #define SDM72_TOTAL_ENERGY 0x0156 //kWh 84 | #define SDM72_SETABLE_TOTAL_ENERGY 0x0180 //kWh 85 | #define SDM72_SETABLE_IMPORT_ENERGY 0x0184 //kWh 86 | #define SDM72_SETABLE_EXPORT_ENERGY 0x0186 //kWh 87 | #define SDM72_IMPORT_POWER 0x0500 //W 88 | #define SDM72_EXPORT_POWER 0x0502 //W 89 | //SDM 120C registers 90 | // https://bg-etech.de/download/manual/SDM120C-Modbus-DE.pdf 91 | #define SDM120C_VOLTAGE 0x0000 //V 92 | #define SDM120C_CURRENT 0x0006 //A 93 | #define SDM120C_POWER 0x000C //W 94 | #define SDM120C_ACTIVE_APPARENT_POWER 0x0012 //VA 95 | #define SDM120C_REACTIVE_APPARENT_POWER 0x0018 //VAR 96 | #define SDM120C_POWER_FACTOR 0x001E // 97 | #define SDM120C_FREQUENCY 0x0046 //Hz 98 | #define SDM120C_IMPORT_ACTIVE_ENERGY 0x0048 //Wh 99 | #define SDM120C_EXPORT_ACTIVE_ENERGY 0x004A //Wh 100 | #define SDM120C_TOTAL_ACTIVE_ENERGY 0x0156 //Wh 101 | //SDM 120 & SDM 120CT registers 102 | // http://www.eastroneurope.com/media/_system/tech_specs/3914/SDM120%20PROTOCOL.pdf 103 | // http://www.eastroneurope.com/media/_system/tech_specs/3915/SDM120CT%20PROTOCOL.pdf 104 | #define SDM120CT_VOLTAGE 0x0000 //V 105 | #define SDM120CT_CURRENT 0x0006 //A 106 | #define SDM120CT_POWER 0x000C //W 107 | #define SDM120CT_APPARENT_POWER 0x0012 //VA 108 | #define SDM120CT_REACTIVE_POWER 0x0018 //VAr 109 | #define SDM120CT_POWER_FACTOR 0x001E //None 110 | #define SDM120CT_PHASE_ANGLE 0x0024 //Degrees 111 | #define SDM120CT_FREQUENCY 0x0046 //Hz 112 | #define SDM120CT_IMPORT_ACTIVE_ENERGY 0x0048 //kWh 113 | #define SDM120CT_EXPORT_ACTIVE_ENERGY 0x004A //kWh 114 | #define SDM120CT_IMPORT_REACTIVE_ENERGY 0x004C //kVArh 115 | #define SDM120CT_EXPORT_REACTIVE_ENERGY 0x004E //kVARh 116 | #define SDM120CT_TOTAL_ACTIVE_ENERGY 0x0156 //kWh 117 | #define SDM120CT_TOTAL_REACTIVE_ENERGY 0x0158 //Kvarh 118 | //SDM 220 registers 119 | #define SDM220T_VOLTAGE 0x0000 //V 120 | #define SDM220T_CURRENT 0x0006 //A 121 | #define SDM220T_POWER 0x000C //W 122 | #define SDM220T_ACTIVE_APPARENT_POWER 0x0012 //VA 123 | #define SDM220T_REACTIVE_APPARENT_POWER 0x0018 //VAR 124 | #define SDM220T_POWER_FACTOR 0x001E // 125 | #define SDM220T_PHASE_ANGLE 0x0024 //DEGREE 126 | #define SDM220T_FREQUENCY 0x0046 //Hz 127 | #define SDM220T_IMPORT_ACTIVE_ENERGY 0x0048 //Wh 128 | #define SDM220T_EXPORT_ACTIVE_ENERGY 0x004A //Wh 129 | #define SDM220T_IMPORT_REACTIVE_ENERGY 0x004C //VARh 130 | #define SDM220T_EXPORT_REACTIVE_ENERGY 0x004E //VARh 131 | #define SDM220T_TOTAL_ACTIVE_ENERGY 0x0156 //Wh 132 | #define SDM220T_TOTAL_REACTIVE_ENERGY 0x0158 //VARh 133 | //SDM 230 registers 134 | #define SDM230_VOLTAGE 0x0000 //V 135 | #define SDM230_CURRENT 0x0006 //A 136 | #define SDM230_POWER 0x000C //W 137 | #define SDM230_ACTIVE_APPARENT_POWER 0x0012 //VA 138 | #define SDM230_REACTIVE_APPARENT_POWER 0x0018 //VAR 139 | #define SDM230_POWER_FACTOR 0x001E // 140 | #define SDM230_PHASE_ANGLE 0x0024 //DEGREE 141 | #define SDM230_FREQUENCY 0x0046 //Hz 142 | #define SDM230_IMPORT_ACTIVE_ENERGY 0x0048 //Wh 143 | #define SDM230_EXPORT_ACTIVE_ENERGY 0x004A //Wh 144 | #define SDM230_IMPORT_REACTIVE_ENERGY 0x004C //VARh 145 | #define SDM230_EXPORT_REACTIVE_ENERGY 0x004E //VARh 146 | #define SDM230_TOTAL_SYSTEM_POWER_DEMAND 0x0054 //W 147 | #define SDM230_MAXIMUM_SYSTEM_POWER_DEMAND 0x0056 //W 148 | #define SDM230_CURRENT_POSITIVE_POWER_DEMAND 0x0058 //W 149 | #define SDM230_MAXIMUM_POSITIVE_POWER_DEMAND 0x005A //W 150 | #define SDM230_CURRENT_REVERSE_POWER_DEMAND 0x005C //W 151 | #define SDM230_MAXIMUM_REVERSE_POWER_DEMAND 0x005E //W 152 | #define SDM230_CURRENT_DEMAND 0x0102 //Amps 153 | #define SDM230_MAXIMUM_CURRENT_DEMAND 0x0108 //Amps 154 | #define SDM230_TOTAL_ACTIVE_ENERGY 0x0156 //kwh 155 | #define SDM230_TOTAL_REACTIVE_ENERGY 0x0158 //kvarh 156 | #define SDM230_CURRENT_RESETTABLE_TOTAL_ACTIVE_ENERGY 0x0180 //Wh 157 | #define SDM230_CURRENT_RESETTABLE_TOTAL_REACTIVE_ENERGY 0x0182 //VARh 158 | //SDM 630 registers 159 | #define SDM630_VOLTAGE1 0x0000 //V 160 | #define SDM630_VOLTAGE2 0x0002 //V 161 | #define SDM630_VOLTAGE3 0x0004 //V 162 | #define SDM630_CURRENT1 0x0006 //A 163 | #define SDM630_CURRENT2 0x0008 //A 164 | #define SDM630_CURRENT3 0x000A //A 165 | #define SDM630_CURRENTSUM 0x0030 //A 166 | #define SDM630_POWER1 0x000C //W 167 | #define SDM630_POWER2 0x000E //W 168 | #define SDM630_POWER3 0x0010 //W 169 | #define SDM630_POWERTOTAL 0x0034 //W 170 | #define SDM630_VOLT_AMPS1 0x0012 //VA 171 | #define SDM630_VOLT_AMPS2 0x0014 //VA 172 | #define SDM630_VOLT_AMPS3 0x0016 //VA 173 | #define SDM630_VOLT_AMPS_TOTAL 0x0038 //VA 174 | #define SDM630_VOLT_AMPS_REACTIVE1 0x0018 //VAr 175 | #define SDM630_VOLT_AMPS_REACTIVE2 0x001A //VAr 176 | #define SDM630_VOLT_AMPS_REACTIVE3 0x001C //VAr 177 | #define SDM630_VOLT_AMPS_REACTIVE_TOTAL 0x003C //VAr 178 | #define SDM630_POWER_FACTOR1 0x001E 179 | #define SDM630_POWER_FACTOR2 0x0020 180 | #define SDM630_POWER_FACTOR3 0x0022 181 | #define SDM630_POWER_FACTOR_TOTAL 0x003E 182 | #define SDM630_PHASE_ANGLE1 0x0024 //Degrees 183 | #define SDM630_PHASE_ANGLE2 0x0026 //Degrees 184 | #define SDM630_PHASE_ANGLE3 0x0028 //Degrees 185 | #define SDM630_PHASE_ANGLE_TOTAL 0x0042 //Degrees 186 | #define SDM630_VOLTAGE_AVERAGE 0x002A //V 187 | #define SDM630_CURRENT_AVERAGE 0x002E //A 188 | #define SDM630_FREQUENCY 0x0046 //HZ 189 | #define SDM630_IMPORT_ACTIVE_ENERGY 0x0048 //Wh 190 | #define SDM630_EXPORT_ACTIVE_ENERGY 0x004A //Wh 191 | #define SDM630_IMPORT_REACTIVE_ENERGY 0x004C //VARh 192 | #define SDM630_EXPORT_REACTIVE_ENERGY 0x004E //VARh 193 | #define SDM630_TOTAL_SYSTEM_POWER_DEMAND 0x0054 //W 194 | #define SDM630_MAXIMUM_TOTAL_SYSTEM_POWER 0x0056 //W 195 | #define SDM630_PHASE_1_LN_VOLTS_THD 0x00EA //% 196 | #define SDM630_PHASE_2_LN_VOLTS_THD 0x00EC //% 197 | #define SDM630_PHASE_3_LN_VOLTS_THD 0x00EE //% 198 | #define SDM630_AVERAGE_VOLTS_THD 0x00F8 //% 199 | #define SDM630_PHASE_1_CURRENT_THD 0x00F0 //% 200 | #define SDM630_PHASE_2_CURRENT_THD 0x00F2 //% 201 | #define SDM630_PHASE_3_CURRENT_THD 0x00F4 //% 202 | #define SDM630_AVERAGE_CURRENT_THD 0x00FA //% 203 | #define SDM630_IMPORT1 0x015a //kWh 204 | #define SDM630_IMPORT2 0x015c //kWh 205 | #define SDM630_IMPORT3 0x015e //kWh 206 | #define SDM630_EXPORT1 0x0160 //kWh 207 | #define SDM630_EXPORT2 0x0162 //kWh 208 | #define SDM630_EXPORT3 0x0164 //kWh 209 | #define SDM630_TOTAL_ENERGY1 0x0166 //kWh 210 | #define SDM630_TOTAL_ENERGY2 0x0168 //kWh 211 | #define SDM630_TOTAL_ENERGY3 0x016a //kWh 212 | 213 | #define SDM_B_05 0x00 //BYTE 5 214 | #define SDM_B_06 0x02 //BYTE 6 215 | //------------------------------------------------------------------------------ 216 | #define SDM_ERR_NO_ERROR 0 //no error 217 | #define SDM_ERR_CRC_ERROR 1 //crc error 218 | #define SDM_ERR_WRONG_BYTES 2 //bytes b0,b1 or b2 wrong 219 | #define SDM_ERR_NOT_ENOUGHT_BYTES 3 //not enough bytes from sdm 220 | #define SDM_ERR_TIMEOUT 4 //timeout 221 | //------------------------------------------------------------------------------ 222 | class SDM { 223 | public: 224 | #if defined ( USE_HARDWARESERIAL ) //hardware serial 225 | #if defined ( ESP8266 ) // on esp8266 226 | SDM(HardwareSerial& serial, long baud = SDM_UART_BAUD, int dere_pin = DERE_PIN, int config = SDM_UART_CONFIG, bool swapuart = SWAPHWSERIAL); 227 | #elif defined ( ESP32 ) // on esp32 228 | SDM(HardwareSerial& serial, long baud = SDM_UART_BAUD, int dere_pin = DERE_PIN, int config = SDM_UART_CONFIG, int8_t rx_pin = SDM_RX_PIN, int8_t tx_pin = SDM_TX_PIN); 229 | #else // on avr 230 | SDM(HardwareSerial& serial, long baud = SDM_UART_BAUD, int dere_pin = DERE_PIN, int config = SDM_UART_CONFIG); 231 | #endif 232 | #else //software serial 233 | #if defined ( ESP8266 ) || defined ( ESP32 ) // on esp8266/esp32 234 | SDM(SoftwareSerial& serial, long baud = SDM_UART_BAUD, int dere_pin = DERE_PIN, int config = SDM_UART_CONFIG, int8_t rx_pin = SDM_RX_PIN, int8_t tx_pin = SDM_TX_PIN); 235 | #else // on avr 236 | SDM(SoftwareSerial& serial, long baud = SDM_UART_BAUD, int dere_pin = DERE_PIN); 237 | #endif 238 | #endif 239 | virtual ~SDM(); 240 | 241 | void begin(void); 242 | float readVal(uint16_t reg, uint8_t node = SDM_B_01); //read value from register = reg and from deviceId = node 243 | uint16_t getErrCode(bool _clear = false); //return last errorcode (optional clear this value, default flase) 244 | uint16_t getErrCount(bool _clear = false); //return total errors count (optional clear this value, default flase) 245 | uint16_t getSuccCount(bool _clear = false); //return total success count (optional clear this value, default false) 246 | void clearErrCode(); //clear last errorcode 247 | void clearErrCount(); //clear total errors count 248 | void clearSuccCount(); //clear total success count 249 | 250 | private: 251 | #if defined ( USE_HARDWARESERIAL ) 252 | HardwareSerial& sdmSer; 253 | #else 254 | SoftwareSerial& sdmSer; 255 | #endif 256 | 257 | #if defined ( USE_HARDWARESERIAL ) 258 | int _config = SDM_UART_CONFIG; 259 | #if defined ( ESP8266 ) 260 | bool _swapuart = SWAPHWSERIAL; 261 | #elif defined ( ESP32 ) 262 | int8_t _rx_pin = -1; 263 | int8_t _tx_pin = -1; 264 | #endif 265 | #else 266 | #if defined ( ESP8266 ) || defined ( ESP32 ) 267 | int _config = SDM_UART_CONFIG; 268 | #endif 269 | int8_t _rx_pin = -1; 270 | int8_t _tx_pin = -1; 271 | #endif 272 | long _baud = SDM_UART_BAUD; 273 | int _dere_pin = DERE_PIN; 274 | uint16_t readingerrcode = SDM_ERR_NO_ERROR; //4 = timeout; 3 = not enough bytes; 2 = number of bytes OK but bytes b0,b1 or b2 wrong, 1 = crc error 275 | uint16_t readingerrcount = 0; //total errors counter 276 | uint32_t readingsuccesscount = 0; //total success counter 277 | uint16_t calculateCRC(uint8_t *array, uint8_t num); 278 | void flush(); //read serial if any old data is available 279 | void dereSet(bool _state = LOW); //for control MAX485 DE/RE pins, LOW receive from SDM, HIGH transmit to SDM 280 | }; 281 | #endif //SDM_h 282 | 283 | //------------------------------------------------------------------------------ 284 | #if defined ( USE_HARDWARESERIAL ) 285 | #if defined ( ESP8266 ) 286 | SDM::SDM(HardwareSerial& serial, long baud, int dere_pin, int config, bool swapuart) : sdmSer(serial) { 287 | this->_baud = baud; 288 | this->_dere_pin = dere_pin; 289 | this->_config = config; 290 | this->_swapuart = swapuart; 291 | } 292 | #elif defined ( ESP32 ) 293 | SDM::SDM(HardwareSerial& serial, long baud, int dere_pin, int config, int8_t rx_pin, int8_t tx_pin) : sdmSer(serial) { 294 | this->_baud = baud; 295 | this->_dere_pin = dere_pin; 296 | this->_config = config; 297 | this->_rx_pin = rx_pin; 298 | this->_tx_pin = tx_pin; 299 | } 300 | #else 301 | SDM::SDM(HardwareSerial& serial, long baud, int dere_pin, int config) : sdmSer(serial) { 302 | this->_baud = baud; 303 | this->_dere_pin = dere_pin; 304 | this->_config = config; 305 | } 306 | #endif 307 | #else 308 | #if defined ( ESP8266 ) || defined ( ESP32 ) 309 | SDM::SDM(SoftwareSerial& serial, long baud, int dere_pin, int config, int8_t rx_pin, int8_t tx_pin) : sdmSer(serial) { 310 | this->_baud = baud; 311 | this->_dere_pin = dere_pin; 312 | this->_config = config; 313 | this->_rx_pin = rx_pin; 314 | this->_tx_pin = tx_pin; 315 | } 316 | #else 317 | SDM::SDM(SoftwareSerial& serial, long baud, int dere_pin) : sdmSer(serial) { 318 | this->_baud = baud; 319 | this->_dere_pin = dere_pin; 320 | } 321 | #endif 322 | #endif 323 | 324 | SDM::~SDM() { 325 | } 326 | 327 | void SDM::begin(void) { 328 | #if defined ( USE_HARDWARESERIAL ) 329 | #if defined ( ESP8266 ) 330 | sdmSer.begin(_baud, (SerialConfig)_config); 331 | #elif defined ( ESP32 ) 332 | sdmSer.begin(_baud, _config, _rx_pin, _tx_pin); 333 | #else 334 | sdmSer.begin(_baud, _config); 335 | #endif 336 | #else 337 | #if defined ( ESP8266 ) || defined ( ESP32 ) 338 | sdmSer.begin(_baud, (SoftwareSerialConfig)_config, _rx_pin, _tx_pin); 339 | #else 340 | sdmSer.begin(_baud); 341 | #endif 342 | #endif 343 | 344 | #if defined ( USE_HARDWARESERIAL ) && defined ( ESP8266 ) 345 | if (_swapuart) 346 | sdmSer.swap(); 347 | #endif 348 | if (_dere_pin != NOT_A_PIN) { 349 | pinMode(_dere_pin, OUTPUT); //set output pin mode for DE/RE pin when used (for control MAX485) 350 | } 351 | dereSet(LOW); //set init state to receive from SDM -> DE Disable, /RE Enable (for control MAX485) 352 | } 353 | 354 | float SDM::readVal(uint16_t reg, uint8_t node) { 355 | uint16_t temp; 356 | unsigned long resptime; 357 | uint8_t sdmarr[FRAMESIZE] = {node, SDM_B_02, 0, 0, SDM_B_05, SDM_B_06, 0, 0, 0}; 358 | float res = NAN; 359 | uint16_t readErr = SDM_ERR_NO_ERROR; 360 | 361 | sdmarr[2] = highByte(reg); 362 | sdmarr[3] = lowByte(reg); 363 | 364 | temp = calculateCRC(sdmarr, FRAMESIZE - 3); //calculate out crc only from first 6 bytes 365 | 366 | sdmarr[6] = lowByte(temp); 367 | sdmarr[7] = highByte(temp); 368 | 369 | #if !defined ( USE_HARDWARESERIAL ) 370 | sdmSer.listen(); //enable softserial rx interrupt 371 | #endif 372 | 373 | flush(); //read serial if any old data is available 374 | 375 | dereSet(HIGH); //transmit to SDM -> DE Enable, /RE Disable (for control MAX485) 376 | 377 | delay(2); //fix for issue (nan reading) by sjfaustino: https://github.com/reaper7/SDM_Energy_Meter/issues/7#issuecomment-272111524 378 | 379 | sdmSer.write(sdmarr, FRAMESIZE - 1); //send 8 bytes 380 | 381 | sdmSer.flush(); //clear out tx buffer 382 | 383 | dereSet(LOW); //receive from SDM -> DE Disable, /RE Enable (for control MAX485) 384 | 385 | resptime = millis() + MAX_MILLIS_TO_WAIT; 386 | 387 | while (sdmSer.available() < FRAMESIZE) { 388 | if (resptime < millis()) { 389 | readErr = SDM_ERR_TIMEOUT; //err debug (4) 390 | break; 391 | } 392 | yield(); 393 | } 394 | 395 | if (readErr == SDM_ERR_NO_ERROR) { //if no timeout... 396 | 397 | if(sdmSer.available() >= FRAMESIZE) { 398 | 399 | for(int n=0; n>= 1; 481 | if (_flag) 482 | _crc ^= 0xA001; 483 | } 484 | } 485 | return _crc; 486 | } 487 | 488 | void SDM::flush() { 489 | uint8_t _i = 0; 490 | while (sdmSer.available() && _i++ < 10) { //read serial if any old data is available 491 | sdmSer.read(); 492 | delay(1); 493 | } 494 | } 495 | 496 | void SDM::dereSet(bool _state) { 497 | if (_dere_pin != NOT_A_PIN) 498 | digitalWrite(_dere_pin, _state); //receive from SDM -> DE Disable, /RE Enable (for control MAX485) 499 | } 500 | --------------------------------------------------------------------------------