diff --git a/.gitignore b/.gitignore index 3511368..3c6e3bc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ # This is an example and may include too much for your use-case. # You can modify this file to suit your needs. /.esphome/ +.esphome/external_components /secrets.yaml /.esphome.bak/ /fonts/ diff --git a/README.md b/README.md index f9f3026..caca689 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -# ESPHome Config Folder - -This folder contains configuration files for ESPHome devices. The `solar` directory is specifically used for managing solar-related ESPHome setups. - -## Structure - -- `source/solar/`: Contains source code files and related resources for solar projects. - -## Usage - -1. Place your ESPHome YAML configuration files in this directory. -2. Use the ESPHome CLI or dashboard to validate and upload configurations to your devices. - +# ESPHome Config Folder + +This folder contains configuration files for ESPHome devices. The `solar` directory is specifically used for managing solar-related ESPHome setups. + +## Structure + +- `source/solar/`: Contains source code files and related resources for solar projects. + +## Usage + +1. Place your ESPHome YAML configuration files in this directory. +2. Use the ESPHome CLI or dashboard to validate and upload configurations to your devices. + For more information, visit the [ESPHome documentation](https://esphome.io/). \ No newline at end of file diff --git a/backup/sthome-ut3-bak.yaml b/backup/sthome-ut3-bak.yaml new file mode 100644 index 0000000..00a99fd --- /dev/null +++ b/backup/sthome-ut3-bak.yaml @@ -0,0 +1,752 @@ +packages: + - !include common/wifi.yaml + - !include common/felicityinverter.yaml + +substitutions: + name: sthome-ut3 + friendly_name: "sthome-ut3" + +esphome: + name: "${name}" + friendly_name: "${friendly_name}" +# on_boot: +# - priority: 600 # This is where most sensors are set up (higher number means higher priority) +# then: +# - uart.write: +# id: inv_uart1 +# data: [0x0D, 0x0A] +# - uart.write: +# id: inv_uart2 +# data: [0x0D, 0x0A] + +#external_components: +# - source: github://pr#8103 +# components: [uart] +# - source: github://pr#8032 +# components: [modbus, modbus_controller] #, growatt_solar] +# refresh: 1h + +globals: + - id: geyser_relay_status + type: bool + restore_value: yes + initial_value: 'false' + + +esp32: + board: nodemcu-32s #esp32dev + framework: + type: arduino #esp-idf + +# Enable logging +logger: + level: VERY_VERBOSE + initial_level: DEBUG + logs: + uart: VERY_VERBOSE + modbus: VERBOSE + modbus_controller: VERBOSE + +# Enable Home Assistant API +api: + encryption: + key: "AIoquKPjpcHa2pcJ0aKxvtpM3mwgZuZhpCPtdVitP2Q=" + +ota: + - platform: esphome + password: "879012af7180c8700cee65fbf18704d1" + +wifi: + manual_ip: + static_ip: 10.0.2.3 + + # Enable fallback hotspot (captive portal) in case wifi connection fails + ap: + ssid: "${name} Fallback Hotspot" + password: "cGXb2DqkwaOr" + +captive_portal: + +uart: + - id: inv_uart1 + rx_pin: GPIO16 + tx_pin: GPIO17 + baud_rate: 2400 + stop_bits: 1 + parity: NONE + debug: + direction: BOTH + dummy_receiver: false + after: + delimiter: "\r" + sequence: + - lambda: UARTDebug::log_hex(direction, bytes, ','); + +# - id: inv_uart2 +# rx_pin: GPIO25 +# tx_pin: GPIO26 +# baud_rate: 2400 +# stop_bits: 1 +# parity: NONE +# debug: +# direction: BOTH +# dummy_receiver: false +# after: +# delimiter: "\r" +# sequence: +# - lambda: UARTDebug::log_hex(direction, bytes, ' '); + +sun: + id: sun_sensor + latitude: !secret latitude + longitude: !secret longitude + +time: + - platform: homeassistant + id: time_source + +switch: + - platform: restart + name: "${name} Restart" + id: "restart_switch" + +modbus: + - id: modbus1 + uart_id: inv_uart1 + # flow_control_pin: GPIO4 + send_wait_time: 1200ms #250ms + disable_crc: false + role: server + +# - id: modbus2 +# uart_id: inv_uart2 +# #flow_control_pin: GPIO27 +# send_wait_time: 1200ms #250ms +# disable_crc: false +# role: server + +modbus_controller: +# - id: modbus_device1 +# modbus_id: modbus1 +# address: 0x01 +# allow_duplicate_commands: False +# command_throttle: 0ms +# update_interval: 10s #30s +# offline_skip_updates: 2 +# max_cmd_retries: 0 +# setup_priority: -10 +# - id: modbus_device2 +# modbus_id: modbus2 +# address: 0x01 +# allow_duplicate_commands: False +# command_throttle: 0ms +# update_interval: 60s #30s +# offline_skip_updates: 2 +# max_cmd_retries: 0 +# setup_priority: -10 + + - modbus_id: modbus1 + address: 0x1 + server_registers: + - address: 0x1100 + value_type: U_WORD + read_lambda: |- + return 0x01; + - address: 0x1101 + value_type: U_WORD + read_lambda: |- + return 0x02; // b0=power-on mode/PowerOnMode 1=standby mode/StandbyMode 2=bypass mode/BypassMode 3=battery mode/BatteryMode 4=fault mode/FaultMode 5=mains mode/LineMode 6=charging mode/PVChargeMode 0=no + - address: 0x1102 + value_type: U_WORD + read_lambda: |- + return 0x02; // No charge 1=Constant current charge/Bulk charge 2=Constant voltage charge/Absorption charge 3=Float charge/Float charge + - address: 0x1103 # Fault Code + value_type: U_WORD + read_lambda: |- + return 0x0; + - address: 0x1104 # PowerFlowMsg + value_type: U_WORD + read_lambda: |- + return 0x0; + - address: 0x1105 # dummy + value_type: U_WORD + read_lambda: |- + return 0x0; + - address: 0x1106 # dummy + value_type: U_DWORD + read_lambda: |- + return 0x0; + - address: 0x1108 # Battery voltage + value_type: U_WORD + read_lambda: |- + return 0x3A; + - address: 0x1109 # Battery current + value_type: S_WORD + read_lambda: |- + return 0xFFC4; // -60A + - address: 0x110A # Battery power + value_type: S_WORD + read_lambda: |- + return 0xED40; // -4800W + - address: 0x110B # dummy + value_type: U_QWORD + read_lambda: |- + return 0; + - address: 0x110F # dummy + value_type: U_DWORD + read_lambda: |- + return 0; + - address: 0x1111 # AC Output voltage + value_type: U_WORD + read_lambda: |- + return 0xE7; // 231V + - address: 0x1112 # dummy + value_type: U_QWORD + read_lambda: |- + return 0; + - address: 0x1116 # dummy + value_type: U_WORD + read_lambda: |- + return 0; + - address: 0x1117 # AC Input voltage + value_type: U_WORD + read_lambda: |- + return 0xE6; // 230V + - address: 0x1118 # dummy + value_type: U_WORD + read_lambda: |- + return 0; + - address: 0x1119 # AC Input frequency + value_type: U_WORD + read_lambda: |- + return 50; // 50Hz + - address: 0x111A # dummy + value_type: U_QWORD + read_lambda: |- + return 0; + - address: 0x111B # dummy + value_type: U_WORD + read_lambda: |- + return 0; + - address: 0x111C # dummy + value_type: U_DWORD + read_lambda: |- + return 0; + - address: 0x111E + value_type: S_WORD + read_lambda: |- + return 100; // 100W + - address: 0x111F + value_type: U_WORD + read_lambda: |- + return 120; // 120VA + - address: 0x1120 + value_type: U_WORD + read_lambda: |- + return 50; // 50% + - address: 0x1121 # dummy + value_type: U_QWORD + read_lambda: |- + return 0; + - address: 0x1125 # dummy + value_type: U_WORD + read_lambda: |- + return 0; + - address: 0x1126 + value_type: U_WORD + read_lambda: |- + return 450; // 450V + - address: 0x1127 # dummy + value_type: U_WORD + read_lambda: |- + return 0; + - address: 0x1128 # dummy + value_type: U_DWORD + read_lambda: |- + return 0; + - address: 0x112A + value_type: S_WORD + read_lambda: |- + return 4812; // 4812W + +# - modbus_id: modbus2 +# server_registers: +# - address: 0x1100 +# value_type: U_WORD +# read_lambda: |- +# return 0x01; +# - address: 0x1101 +# value_type: U_WORD +# read_lambda: |- +# return 0x02; // b0=power-on mode/PowerOnMode 1=standby mode/StandbyMode 2=bypass mode/BypassMode 3=battery mode/BatteryMode 4=fault mode/FaultMode 5=mains mode/LineMode 6=charging mode/PVChargeMode 0=no +# - address: 0x1102 +# value_type: U_WORD +# read_lambda: |- +# return 0x02; // No charge 1=Constant current charge/Bulk charge 2=Constant voltage charge/Absorption charge 3=Float charge/Float charge +# - address: 0x1103 # Fault Code +# value_type: U_WORD +# read_lambda: |- +# return 0x0; +# - address: 0x1104 # PowerFlowMsg +# value_type: U_WORD +# read_lambda: |- +# return 0x0; +# - address: 0x1105 # dummy +# value_type: U_WORD +# read_lambda: |- +# return 0x0; +# - address: 0x1106 # dummy +# value_type: U_DWORD +# read_lambda: |- +# return 0x0; +# - address: 0x1108 # Battery voltage +# value_type: U_WORD +# read_lambda: |- +# return 0x3A; +# - address: 0x1109 # Battery current +# value_type: S_WORD +# read_lambda: |- +# return 0xFFC4; // -60A +# - address: 0x110A # Battery power +# value_type: S_WORD +# read_lambda: |- +# return 0xED40; // -4800W +# - address: 0x110B # dummy +# value_type: U_QWORD +# read_lambda: |- +# return 0; +# - address: 0x110F # dummy +# value_type: U_DWORD +# read_lambda: |- +# return 0; +# - address: 0x1111 # AC Output voltage +# value_type: U_WORD +# read_lambda: |- +# return 0xE7; // 231V +# - address: 0x1112 # dummy +# value_type: U_QWORD +# read_lambda: |- +# return 0; +# - address: 0x1116 # dummy +# value_type: U_WORD +# read_lambda: |- +# return 0; +# - address: 0x1117 # AC Input voltage +# value_type: U_WORD +# read_lambda: |- +# return 0xE6; // 230V +# - address: 0x1118 # dummy +# value_type: U_WORD +# read_lambda: |- +# return 0; +# - address: 0x1119 # AC Input frequency +# value_type: U_WORD +# read_lambda: |- +# return 50; // 50Hz +# - address: 0x111A # dummy +# value_type: U_QWORD +# read_lambda: |- +# return 0; +# - address: 0x111B # dummy +# value_type: U_WORD +# read_lambda: |- +# return 0; +# - address: 0x111C # dummy +# value_type: U_DWORD +# read_lambda: |- +# return 0; +# - address: 0x111E +# value_type: S_WORD +# read_lambda: |- +# return 100; // 100W +# - address: 0x111F +# value_type: U_WORD +# read_lambda: |- +# return 120; // 120VA +# - address: 0x1120 +# value_type: U_WORD +# read_lambda: |- +# return 50; // 50% +# - address: 0x1121 # dummy +# value_type: U_QWORD +# read_lambda: |- +# return 0; +# - address: 0x1125 # dummy +# value_type: U_WORD +# read_lambda: |- +# return 0; +# - address: 0x1126 +# value_type: U_WORD +# read_lambda: |- +# return 450; // 450V +# - address: 0x1127 # dummy +# value_type: U_WORD +# read_lambda: |- +# return 0; +# - address: 0x1128 # dummy +# value_type: U_DWORD +# read_lambda: |- +# return 0; +# - address: 0x112A +# value_type: S_WORD +# read_lambda: |- +# return 4812; // 4812W + +#text_sensor: +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 SerialNo" +# register_type: holding +# address: ${Felicity_Inv_SerialNo} # 0xF804 +# response_size: 7 +# register_count: 7 +# raw_encode: HEXBYTES +# +##- platform: modbus_controller +## modbus_controller_id: modbus_device2 +## name: "Inverter2 SerialNo" +## register_type: holding +## address: ${Felicity_Inv_SerialNo} # 0xF804 +## response_size: 7 +## register_count: 7 +## raw_encode: HEXBYTES +# +#sensor: +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Type" +# id: inverter1_type +# register_type: holding +# address: ${Felicity_Inv_Type} # 0xF800 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Sub Type" +# register_type: holding +# address: ${Felicity_Inv_SubType} # 0xF801 +# value_type: U_WORD +# register_count: 3 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 CPU1 F/W Version" +# register_type: holding +# address: ${Felicity_Inv_CPU1_FW_Version} # 0xF80B +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 CPU2 F/W Version" +# register_type: holding +# address: ${Felicity_Inv_CPU2_FW_Version} # 0xF80C +# value_type: U_WORD +# register_count: 3 + +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 SettingDataSn" +# register_type: holding +# address: ${Felicity_Inv_SettingDataSn} # 0x1100 +# value_type: U_WORD +# register_count: 1 +## lambda: |- +## if (!isnan(id(inverter1_type).state)) { +## return x; // Update the sensor's value if the condition is true +## } else { +## return NAN; // Return NaN to skip updating if the condition is false +## } +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Working Mode" +# register_type: holding +# address: ${Felicity_Inv_WorkingMode} # 0x1101 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Charge Mode" +# register_type: holding +# address: ${Felicity_Inv_BatteryChargingStage} # 0x1102 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Fault Code" +# register_type: holding +# address: ${Felicity_Inv_FaultCode} # 0x1103 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Power Flow" +# register_type: holding +# address: ${Felicity_Inv_PowerFlowMsg} # 0x1104 +# value_type: U_WORD +# register_count: 4 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Battery Voltage" +# register_type: holding +# address: ${Felicity_Inv_BatteryVoltage} # 0x1108 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Battery Current" +# register_type: holding +# address: ${Felicity_Inv_BatteryCurrent} # 0x1109 +# value_type: S_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 BatteryPower" +# register_type: holding +# address: ${Felicity_Inv_BatteryPower} # 0x110A +# value_type: S_WORD +# register_count: 7 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 AC Output Voltage" +# register_type: holding +# address: ${Felicity_Inv_ACOutputVoltage} # 0x1111 +# value_type: U_WORD +# register_count: 6 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 AC Input Voltage" +# register_type: holding +# address: ${Felicity_Inv_ACInputVoltage} # 0x1117 +# value_type: U_WORD +# register_count: 2 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 AC Input Frequency" +# register_type: holding +# address: ${Felicity_Inv_ACInputFrequency} # 0x1119 +# value_type: U_WORD +# register_count: 5 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 AC Output Active Power" +# register_type: holding +# address: ${Felicity_Inv_ACOutputActivePower} # 0x111E +# value_type: S_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 AC Output Apparent Power" +# register_type: holding +# address: ${Felicity_Inv_ACOutputApparentPower} # 0x111F +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 Load Percentage" +# register_type: holding +# address: ${Felicity_Inv_LoadPercentage} # 0x1120 +# value_type: U_WORD +# register_count: 6 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 PV Input Voltage" +# register_type: holding +# address: ${Felicity_Inv_PVInputVoltage} # 0x1126 +# value_type: U_WORD +# register_count: 4 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device1 +# name: "Inverter1 PV Input Power" +# register_type: holding +# address: ${Felicity_Inv_PVInputPower} # 0x112A +# value_type: S_WORD +# register_count: 1 + + +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Type" +# register_type: holding +# address: ${Felicity_Inv_Type} # 0xF800 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Sub Type" +# register_type: holding +# address: ${Felicity_Inv_SubType} # 0xF801 +# value_type: U_WORD +# register_count: 1 + +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Dummy" +# register_type: holding +# address: 0xF802 +# value_type: U_WORD +# register_count: 2 + +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 CPU1 F/W Version" +# register_type: holding +# address: ${Felicity_Inv_CPU1_FW_Version} # 0xF80B +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 CPU2 F/W Version" +# register_type: holding +# address: ${Felicity_Inv_CPU2_FW_Version} # 0xF80C +# value_type: U_WORD +# register_count: 3 + +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 SettingDataSn" +# register_type: holding +# address: ${Felicity_Inv_SettingDataSn} # 0x1100 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Working Mode" +# register_type: holding +# address: ${Felicity_Inv_WorkingMode} # 0x1101 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Charge Mode" +# register_type: holding +# address: ${Felicity_Inv_BatteryChargingStage} # 0x1102 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Fault Code" +# register_type: holding +# address: ${Felicity_Inv_FaultCode} # 0x1103 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Power Flow" +# register_type: holding +# address: ${Felicity_Inv_PowerFlowMsg} # 0x1104 +# value_type: U_WORD +# register_count: 4 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Battery Voltage" +# register_type: holding +# address: ${Felicity_Inv_BatteryVoltage} # 0x1108 +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Battery Current" +# register_type: holding +# address: ${Felicity_Inv_BatteryCurrent} # 0x1109 +# value_type: S_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 BatteryPower" +# register_type: holding +# address: ${Felicity_Inv_BatteryPower} # 0x110A +# value_type: S_WORD +# register_count: 7 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 AC Output Voltage" +# register_type: holding +# address: ${Felicity_Inv_ACOutputVoltage} # 0x1111 +# value_type: U_WORD +# register_count: 6 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 AC Input Voltage" +# register_type: holding +# address: ${Felicity_Inv_ACInputVoltage} # 0x1117 +# value_type: U_WORD +# register_count: 2 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 AC Input Frequency" +# register_type: holding +# address: ${Felicity_Inv_ACInputFrequency} # 0x1119 +# value_type: U_WORD +# register_count: 5 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 AC Output Active Power" +# register_type: holding +# address: ${Felicity_Inv_ACOutputActivePower} # 0x111E +# value_type: S_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 AC Output Apparent Power" +# register_type: holding +# address: ${Felicity_Inv_ACOutputApparentPower} # 0x111F +# value_type: U_WORD +# register_count: 1 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 Load Percentage" +# register_type: holding +# address: ${Felicity_Inv_LoadPercentage} # 0x1120 +# value_type: U_WORD +# register_count: 6 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 PV Input Voltage" +# register_type: holding +# address: ${Felicity_Inv_PVInputVoltage} # 0x1126 +# value_type: U_WORD +# register_count: 4 +# +#- platform: modbus_controller +# modbus_controller_id: modbus_device2 +# name: "Inverter2 PV Input Power" +# register_type: holding +# address: ${Felicity_Inv_PVInputPower} # 0x112A +# value_type: S_WORD +# register_count: 1 + + + \ No newline at end of file diff --git a/sthome-ut9-bak.yml b/backup/sthome-ut9-bak.yml similarity index 100% rename from sthome-ut9-bak.yml rename to backup/sthome-ut9-bak.yml diff --git a/sthome-ut9_bak.yml b/backup/sthome-ut9_bak.yml similarity index 100% rename from sthome-ut9_bak.yml rename to backup/sthome-ut9_bak.yml diff --git a/common/time.yaml b/common/time.yaml index 00b9f07..b8ffc70 100644 --- a/common/time.yaml +++ b/common/time.yaml @@ -1,102 +1,102 @@ -# https://community.home-assistant.io/t/display-manually-set-rtc-ds3231-time-in-esphome-sntp-sync-every-12-hours-need-help-with-web-interface/868801 -# miloit -time: - - platform: sntp - id: sntp_time - - -web_server: - port: 80 - -custom_component: - - lambda: |- - class DS3231Component : public PollingComponent { - public: - DS3231Component(esphome::time::RealTimeClock *rtc) : PollingComponent(10000), rtc_(rtc) {} - - void setup() override { - if (!Wire.requestFrom(0x68, 1)) { - ESP_LOGE("DS3231", "RTC not found at I2C address 0x68"); - return; - } - ESP_LOGI("DS3231", "RTC found at I2C address 0x68"); - - auto now = this->rtc_->now(); - if (now.is_valid()) { - set_time(now.year, now.month, now.day_of_month, now.hour, now.minute, now.second, now.day_of_week); - ESP_LOGI("DS3231", "RTC time set to %04d-%02d-%02d %02d:%02d:%02d", - now.year, now.month, now.day_of_month, now.hour, now.minute, now.second); - } else { - ESP_LOGE("DS3231", "SNTP time is not valid; cannot set RTC"); - } - } - - void update() override { - auto time = get_time(); - if (time.year > 0) { - ESP_LOGI("DS3231", "Current RTC Time: %04d-%02d-%02d %02d:%02d:%02d", - time.year, time.month, time.day, time.hour, time.minute, time.second); - } else { - ESP_LOGE("DS3231", "Failed to read time from RTC"); - } - } - - void set_time(int year, int month, int day, int hour, int minute, int second, int day_of_week) { - Wire.beginTransmission(0x68); - Wire.write(0); // Start at register 0 - Wire.write(dec_to_bcd(second)); // Seconds - Wire.write(dec_to_bcd(minute)); // Minutes - Wire.write(dec_to_bcd(hour)); // Hours - Wire.write(dec_to_bcd(day_of_week)); // Day of the week - Wire.write(dec_to_bcd(day)); // Day of the month - Wire.write(dec_to_bcd(month)); // Month - Wire.write(dec_to_bcd(year - 2000)); // Year - Wire.endTransmission(); - } - - struct Time { - int year; - int month; - int day; - int hour; - int minute; - int second; - int day_of_week; - }; - - Time get_time() { - Wire.beginTransmission(0x68); - Wire.write(0); // Start at register 0 - Wire.endTransmission(); - - if (Wire.requestFrom(0x68, 7) != 7) { - ESP_LOGE("DS3231", "Failed to read time registers"); - return Time{0, 0, 0, 0, 0, 0, 0}; - } - - uint8_t second = bcd_to_dec(Wire.read()); - uint8_t minute = bcd_to_dec(Wire.read()); - uint8_t hour = bcd_to_dec(Wire.read()); - uint8_t day_of_week = bcd_to_dec(Wire.read()); - uint8_t day = bcd_to_dec(Wire.read()); - uint8_t month = bcd_to_dec(Wire.read()); - uint16_t year = bcd_to_dec(Wire.read()) + 2000; - - return Time{year, month, day, hour, minute, second, day_of_week}; - } - - private: - esphome::time::RealTimeClock *rtc_; - - uint8_t dec_to_bcd(int val) { - return ((val / 10 * 16) + (val % 10)); - } - - int bcd_to_dec(uint8_t val) { - return ((val / 16 * 10) + (val % 16)); - } - }; - - auto my_rtc = new DS3231Component(id(sntp_time)); - App.register_component(my_rtc); +# https://community.home-assistant.io/t/display-manually-set-rtc-ds3231-time-in-esphome-sntp-sync-every-12-hours-need-help-with-web-interface/868801 +# miloit +time: + - platform: sntp + id: sntp_time + + +web_server: + port: 80 + +custom_component: + - lambda: |- + class DS3231Component : public PollingComponent { + public: + DS3231Component(esphome::time::RealTimeClock *rtc) : PollingComponent(10000), rtc_(rtc) {} + + void setup() override { + if (!Wire.requestFrom(0x68, 1)) { + ESP_LOGE("DS3231", "RTC not found at I2C address 0x68"); + return; + } + ESP_LOGI("DS3231", "RTC found at I2C address 0x68"); + + auto now = this->rtc_->now(); + if (now.is_valid()) { + set_time(now.year, now.month, now.day_of_month, now.hour, now.minute, now.second, now.day_of_week); + ESP_LOGI("DS3231", "RTC time set to %04d-%02d-%02d %02d:%02d:%02d", + now.year, now.month, now.day_of_month, now.hour, now.minute, now.second); + } else { + ESP_LOGE("DS3231", "SNTP time is not valid; cannot set RTC"); + } + } + + void update() override { + auto time = get_time(); + if (time.year > 0) { + ESP_LOGI("DS3231", "Current RTC Time: %04d-%02d-%02d %02d:%02d:%02d", + time.year, time.month, time.day, time.hour, time.minute, time.second); + } else { + ESP_LOGE("DS3231", "Failed to read time from RTC"); + } + } + + void set_time(int year, int month, int day, int hour, int minute, int second, int day_of_week) { + Wire.beginTransmission(0x68); + Wire.write(0); // Start at register 0 + Wire.write(dec_to_bcd(second)); // Seconds + Wire.write(dec_to_bcd(minute)); // Minutes + Wire.write(dec_to_bcd(hour)); // Hours + Wire.write(dec_to_bcd(day_of_week)); // Day of the week + Wire.write(dec_to_bcd(day)); // Day of the month + Wire.write(dec_to_bcd(month)); // Month + Wire.write(dec_to_bcd(year - 2000)); // Year + Wire.endTransmission(); + } + + struct Time { + int year; + int month; + int day; + int hour; + int minute; + int second; + int day_of_week; + }; + + Time get_time() { + Wire.beginTransmission(0x68); + Wire.write(0); // Start at register 0 + Wire.endTransmission(); + + if (Wire.requestFrom(0x68, 7) != 7) { + ESP_LOGE("DS3231", "Failed to read time registers"); + return Time{0, 0, 0, 0, 0, 0, 0}; + } + + uint8_t second = bcd_to_dec(Wire.read()); + uint8_t minute = bcd_to_dec(Wire.read()); + uint8_t hour = bcd_to_dec(Wire.read()); + uint8_t day_of_week = bcd_to_dec(Wire.read()); + uint8_t day = bcd_to_dec(Wire.read()); + uint8_t month = bcd_to_dec(Wire.read()); + uint16_t year = bcd_to_dec(Wire.read()) + 2000; + + return Time{year, month, day, hour, minute, second, day_of_week}; + } + + private: + esphome::time::RealTimeClock *rtc_; + + uint8_t dec_to_bcd(int val) { + return ((val / 10 * 16) + (val % 10)); + } + + int bcd_to_dec(uint8_t val) { + return ((val / 16 * 10) + (val % 16)); + } + }; + + auto my_rtc = new DS3231Component(id(sntp_time)); + App.register_component(my_rtc); return {}; \ No newline at end of file diff --git a/components/ads131m08/README.md b/components/ads131m08/README.md index e2591b6..0a35b89 100644 --- a/components/ads131m08/README.md +++ b/components/ads131m08/README.md @@ -1,57 +1,57 @@ -# ESPHome config/components/ads131m08 - -This folder contains source code files and related resources for external ads131m08 component. - -## Example .yaml config - ---- - -```yaml -external_components: - - source: - type: local - path: components # Path relative to this YAML file - components: [ ads131m08 ] - -ads131m08: - id: highres_adc - cs_pin: GPIO5 - drdy_pin: GPIO10 - vref: 1.25 - -sensor: - - platform: ads131m08 - ads_hub_id: highres_adc - channel: 0 - name: "ADS Channel 0 Voltage" - - platform: ads131m08 - ads_hub_id: highres_adc - channel: 1 - name: "ADS Channel 1 Voltage" - - platform: ads131m08 - ads_hub_id: highres_adc - channel: 2 - name: "ADS Channel 2 Voltage" - - platform: ads131m08 - ads_hub_id: highres_adc - channel: 3 - name: "ADS Channel 3 Voltage" - - platform: ads131m08 - ads_hub_id: highres_adc - channel: 4 - name: "ADS Channel 4 Voltage" - - platform: ads131m08 - ads_hub_id: highres_adc - channel: 5 - name: "ADS Channel 5 Voltage" - - platform: ads131m08 - ads_hub_id: highres_adc - channel: 6 - name: "ADS Channel 6 Voltage" - - platform: ads131m08 - ads_hub_id: highres_adc - channel: 7 - name: "ADS Channel 7 Voltage" -``` - +# ESPHome config/components/ads131m08 + +This folder contains source code files and related resources for external ads131m08 component. + +## Example .yaml config + +--- + +```yaml +external_components: + - source: + type: local + path: components # Path relative to this YAML file + components: [ ads131m08 ] + +ads131m08: + id: highres_adc + cs_pin: GPIO5 + drdy_pin: GPIO10 + vref: 1.25 + +sensor: + - platform: ads131m08 + ads_hub_id: highres_adc + channel: 0 + name: "ADS Channel 0 Voltage" + - platform: ads131m08 + ads_hub_id: highres_adc + channel: 1 + name: "ADS Channel 1 Voltage" + - platform: ads131m08 + ads_hub_id: highres_adc + channel: 2 + name: "ADS Channel 2 Voltage" + - platform: ads131m08 + ads_hub_id: highres_adc + channel: 3 + name: "ADS Channel 3 Voltage" + - platform: ads131m08 + ads_hub_id: highres_adc + channel: 4 + name: "ADS Channel 4 Voltage" + - platform: ads131m08 + ads_hub_id: highres_adc + channel: 5 + name: "ADS Channel 5 Voltage" + - platform: ads131m08 + ads_hub_id: highres_adc + channel: 6 + name: "ADS Channel 6 Voltage" + - platform: ads131m08 + ads_hub_id: highres_adc + channel: 7 + name: "ADS Channel 7 Voltage" +``` + For more information, visit the [ESPHome documentation](https://esphome.io/). \ No newline at end of file diff --git a/components/ads131m08/__init__.py b/components/ads131m08/__init__.py index 04cb856..33705e3 100644 --- a/components/ads131m08/__init__.py +++ b/components/ads131m08/__init__.py @@ -1,29 +1,29 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome import pins -from esphome.components import spi -from esphome.const import ( - CONF_ID -) - -CONF_DRDY_PIN = "drdy_pin" -CONF_REFERENCE_VOLTAGE = "reference_voltage" - -DEPENDENCIES = ["spi"] -ads131m08_ns = cg.esphome_ns.namespace("ads131m08") -ADS131M08Hub = ads131m08_ns.class_("ADS131M08Hub", cg.Component, spi.SPIDevice) - -CONFIG_SCHEMA = cv.Schema({ - cv.GenerateID(): cv.declare_id(ADS131M08Hub), - cv.Required(CONF_DRDY_PIN): pins.internal_gpio_input_pin_schema, - cv.Optional(CONF_REFERENCE_VOLTAGE, default=1.2): cv.float_range(min=1.1, max=1.3), -}).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema(cs_pin_required=True)) - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - await spi.register_spi_device(var, config) - drdy = await cg.gpio_pin_expression(config[CONF_DRDY_PIN]) - reference_voltage = config[CONF_REFERENCE_VOLTAGE] - cg.add(var.set_reference_voltage(reference_voltage)) - cg.add(var.set_drdy_pin(drdy)) +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import spi +from esphome.const import ( + CONF_ID +) + +CONF_DRDY_PIN = "drdy_pin" +CONF_REFERENCE_VOLTAGE = "reference_voltage" + +DEPENDENCIES = ["spi"] +ads131m08_ns = cg.esphome_ns.namespace("ads131m08") +ADS131M08Hub = ads131m08_ns.class_("ADS131M08Hub", cg.Component, spi.SPIDevice) + +CONFIG_SCHEMA = cv.Schema({ + cv.GenerateID(): cv.declare_id(ADS131M08Hub), + cv.Required(CONF_DRDY_PIN): pins.internal_gpio_input_pin_schema, + cv.Optional(CONF_REFERENCE_VOLTAGE, default=1.2): cv.float_range(min=1.1, max=1.3), +}).extend(cv.COMPONENT_SCHEMA).extend(spi.spi_device_schema(cs_pin_required=True)) + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await spi.register_spi_device(var, config) + drdy = await cg.gpio_pin_expression(config[CONF_DRDY_PIN]) + reference_voltage = config[CONF_REFERENCE_VOLTAGE] + cg.add(var.set_reference_voltage(reference_voltage)) + cg.add(var.set_drdy_pin(drdy)) diff --git a/components/ads131m08/ads131m08.cpp b/components/ads131m08/ads131m08.cpp index 473e5a6..55853f9 100644 --- a/components/ads131m08/ads131m08.cpp +++ b/components/ads131m08/ads131m08.cpp @@ -1,851 +1,851 @@ -#include "ads131m08.h" - -namespace esphome { -namespace ads131m08 { - -static const char *const TAG = "ads131m08"; - - -void ADS131M08Hub::setup() -{ - // Initialize SPI with correct settings for ADS131M08 - // SPI mode 1: CPOL=0, CPHA=1 - this->spi_setup(); - // not sure if next few lines are needed here or is it handled in spi_setup() - SPI.begin(); - SPI.setDataMode(SPI_MODE1); - SPI.setBitOrder(MSBFIRST); - SPI.setClockDivider(SPI_CLOCK_DIV8); // Adjust clock speed as needed - this->drdy_pin_->setup(); - this->drdy_pin_->pin_mode(esphome::gpio::FLAG_INPUT | esphome::gpio::FLAG_PULLUP); - this->drdy_pin_->attach_interrupt(&ADS131M08Hub::isr, this, gpio::INTERRUPT_FALLING_EDGE); - this->initialize_ads131m08(); -} - -void ADS131M08Hub::initialize_ads131m08() -{ - // Send RESET command - SPI.transfer(0x06); - delay(1); - - // Send UNLOCK command - SPI.transfer(0x55); - SPI.transfer(0x55); - - // Configure registers as needed (example: set gain, etc.) - // Write to MODE register for continuous conversion, disable internal reference (use external MAX6070AAUT12+T at 1.25V) - write_register(0x02, 0x0000); // MODE register, continuous mode, INTREF_EN = 0 - - // Wait for external reference to settle - delay(100); - - // Start conversions - SPI.transfer(0x08); // START command -} - -void ADS131M08Hub::write_register(uint8_t reg, uint16_t value) -{ - SPI.transfer(0x40 | reg); // WREG command - SPI.transfer(0x00); // Number of registers - 1 (0 for one register) - SPI.transfer((value >> 8) & 0xFF); - SPI.transfer(value & 0xFF); -} - -void IRAM_ATTR ADS131M08Hub::isr(ADS131M08Hub *arg) -{ - arg->txf_init(); // implementing datasheet recommended TXF init in ISR - arg->data_ready_ = true; -} - -void ADS131M08Hub::loop() -{ - if (this->data_ready_) { - this->data_ready_ = false; - this->read_data_(); - } -} - -// ********************** from datasheet ************************ -void ADS131M08Hub::txf_init() -{ - if (firstRead) { - // Clear the ADC's 2-deep FIFO on the first read - for (int i = 0; i sensors_[ch] != nullptr) { - int offset = ch * 3; - int32_t raw = (data_buffer_[offset] << 16) | (data_buffer_[offset + 1] << 8) | data_buffer_[offset + 2]; - if (raw & 0x800000) - raw |= 0xFF000000; // Sign extend - float v = (raw / 8388608.0) * this->reference_voltage_; // 2^23 = 8388608, Vref = 1.25V (MAX6070AAUT12+T) - this->sensors_[ch]->publish_state(v); - } - } -} -*/ -void ADS131M08Hub::read_data_() -{ - this->enable(); - // ADS131M08 Frame: 1 Status Word + 8 Channel Words + 1 CRC Word (24-bit words) - uint8_t frame[30]; // 10 words * 3 bytes - this->read_array(frame, 30); - this->disable(); - - for (int i = 0; i < 8; i++) { - if (this->sensors_[i] != nullptr) { - // Convert 24-bit two's complement to float (Simplified) - int32_t raw = (frame[3+(i*3)] << 16) | (frame[4+(i*3)] << 8) | frame[5+(i*3)]; - if (raw & 0x800000) - raw |= 0xFF000000; // Sign extend - this->sensors_[i]->publish_state(raw * (this->reference_voltage_ / 8388608.0)); // 2^23 = 8388608, Vref = 1.25V ( for MAX6070AAUT12+T ) - } - } -} - -// =============== from tpcorrea ================= -ADS131M08Hub::ADS131M08Hub() : csPin(0), drdyPin(0), clkPin(0), misoPin(0), mosiPin(0), resetPin(0) -{ - for( uint16_t i = 0U; i < 8; i++){ - fullScale.ch[i].f = 1.2; // +-1.2V - pgaGain[i] = ADS131M08_PgaGain::PGA_1; - resultFloat.ch[i].f = 0.0; - resultRaw.ch[i].u[0] = 0U; - resultRaw.ch[i].u[1] = 0U; - } - -} - -uint8_t ADS131M08Hub::writeRegister(uint8_t address, uint16_t value) -{ - uint16_t res; - uint8_t addressRcv; - uint8_t bytesRcv; - uint16_t cmd = 0; - - digitalWrite(csPin, LOW); - delayMicroseconds(1); - - cmd = (CMD_WRITE_REG) | (address << 7) | 0; - - //res = spi.transfer16(cmd); - spi.transfer16(cmd); - spi.transfer(0x00); - - spi.transfer16(value); - spi.transfer(0x00); - - for(int i = 0; i < 8; i++) - { - spi.transfer16(0x0000); - spi.transfer(0x00); - } - - res = spi.transfer16(0x0000); - spi.transfer(0x00); - - for(int i = 0; i < 9; i++) - { - spi.transfer16(0x0000); - spi.transfer(0x00); - } - - delayMicroseconds(1); - digitalWrite(csPin, HIGH); - - addressRcv = (res & REGMASK_CMD_READ_REG_ADDRESS) >> 7; - bytesRcv = (res & REGMASK_CMD_READ_REG_BYTES); - - if (addressRcv == address) - { - return bytesRcv + 1; - } - return 0; -} - -void ADS131M08Hub::writeRegisterMasked(uint8_t address, uint16_t value, uint16_t mask) -{ - // Escribe un valor en el registro, aplicando la mascara para tocar unicamente los bits necesarios. - // No realiza el corrimiento de bits (shift), hay que pasarle ya el valor corrido a la posicion correcta - - // Leo el contenido actual del registro - uint16_t register_contents = readRegister(address); - - // Cambio bit aa bit la mascara (queda 1 en los bits que no hay que tocar y 0 en los bits a modificar) - // Se realiza un AND co el contenido actual del registro. Quedan "0" en la parte a modificar - register_contents = register_contents & ~mask; - - // se realiza un OR con el valor a cargar en el registro. Ojo, valor debe estar en el posicion (shitf) correcta - register_contents = register_contents | value; - - // Escribo nuevamente el registro - writeRegister(address, register_contents); -} - -uint16_t ADS131M08Hub::readRegister(uint8_t address) -{ - uint16_t cmd; - uint16_t data; - - cmd = CMD_READ_REG | (address << 7 | 0); - - digitalWrite(csPin, LOW); - delayMicroseconds(1); - - //data = spi.transfer16(cmd); - spi.transfer16(cmd); - spi.transfer(0x00); - - for(int i = 0; i < 9; i++) - { - spi.transfer16(0x0000); - spi.transfer(0x00); - } - - data = spi.transfer16(0x0000); - spi.transfer(0x00); - - for(int i = 0; i < 9; i++) - { - spi.transfer16(0x0000); - spi.transfer(0x00); - } - - delayMicroseconds(1); - digitalWrite(csPin, HIGH); - return data; -} - -void ADS131M08Hub::begin(uint8_t clk_pin, uint8_t miso_pin, uint8_t mosi_pin, uint8_t cs_pin, uint8_t drdy_pin, uint8_t reset_pin) -{ - // Set pins up - csPin = cs_pin; - drdyPin = drdy_pin; - clkPin = clk_pin; - misoPin = miso_pin; - mosiPin = mosi_pin; - resetPin = reset_pin; - - spi = SPIClass(mosi_pin, miso_pin, clk_pin, cs_pin); - spi.begin(); - spi.beginTransaction(settings); - // Configure chip select as an output - pinMode(csPin, OUTPUT); - pinMode(resetPin, OUTPUT); - // Configure DRDY as an input - pinMode(drdyPin, INPUT); -} - -int8_t ADS131M08Hub::isDataReadySoft(byte channel) -{ - if (channel == 0) - { - return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY0); - } - else if (channel == 1) - { - return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY1); - } - else if (channel == 2) - { - return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY2); - } - else if (channel == 3) - { - return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY3); - } - else if (channel == 4) - { - return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY4); - } - else if (channel == 5) - { - return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY5); - } - else if (channel == 6) - { - return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY6); - } - else if (channel == 7) - { - return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY7); - } - else - { - return -1; - } -} - -bool ADS131M08Hub::isResetStatus(void) -{ - return (readRegister(REG_STATUS) & REGMASK_STATUS_RESET); -} - -bool ADS131M08Hub::isLockSPI(void) -{ - return (readRegister(REG_STATUS) & REGMASK_STATUS_LOCK); -} - -bool ADS131M08Hub::setDrdyFormat(uint8_t drdyFormat) -{ - if (drdyFormat > 1) - { - return false; - } - else - { - writeRegisterMasked(REG_MODE, drdyFormat, REGMASK_MODE_DRDY_FMT); - return true; - } -} - -bool ADS131M08Hub::setDrdyStateWhenUnavailable(uint8_t drdyState) -{ - if (drdyState > 1) - { - return false; - } - else - { - writeRegisterMasked(REG_MODE, drdyState < 1, REGMASK_MODE_DRDY_HiZ); - return true; - } -} - -bool ADS131M08Hub::setPowerMode(uint8_t powerMode) -{ - if (powerMode > 3) - { - return false; - } - else - { - writeRegisterMasked(REG_CLOCK, powerMode, REGMASK_CLOCK_PWR); - return true; - } -} - -bool ADS131M08Hub::setOsr(uint16_t osr) -{ - if (osr > 7) - { - return false; - } - else - { - writeRegisterMasked(REG_CLOCK, osr << 2 , REGMASK_CLOCK_OSR); - return true; - } -} - -void ADS131M08Hub::setFullScale(uint8_t channel, float scale) -{ - if (channel > 7) { - return; - } - - this->fullScale.ch[channel].f = scale; - -} - -float ADS131M08Hub::getFullScale(uint8_t channel) -{ - if (channel > 7) { - return 0.0; - } - - return this->fullScale.ch[channel].f; - -} - -void ADS131M08Hub::reset() -{ - digitalWrite(this->resetPin, LOW); - delay(10); - digitalWrite(this->resetPin, HIGH); -} - -bool ADS131M08Hub::setChannelEnable(uint8_t channel, uint16_t enable) -{ - if (channel > 7) - { - return false; - } - if (channel == 0) - { - writeRegisterMasked(REG_CLOCK, enable << 8, REGMASK_CLOCK_CH0_EN); - return true; - } - else if (channel == 1) - { - writeRegisterMasked(REG_CLOCK, enable << 9, REGMASK_CLOCK_CH1_EN); - return true; - } - else if (channel == 2) - { - writeRegisterMasked(REG_CLOCK, enable << 10, REGMASK_CLOCK_CH2_EN); - return true; - } - else if (channel == 3) - { - writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH3_EN); - return true; - } - else if (channel == 4) - { - writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH4_EN); - return true; - } - else if (channel == 5) - { - writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH5_EN); - return true; - } - else if (channel == 6) - { - writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH6_EN); - return true; - } - else if (channel == 7) - { - writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH7_EN); - return true; - } - return false; -} - -bool ADS131M08Hub::setChannelPGA(uint8_t channel, ADS131M08_PgaGain pga) -{ uint16_t pgaCode = (uint16_t) pga; - - if (channel > 7) - { - return false; - } - if (channel == 0) - { - writeRegisterMasked(REG_GAIN1, pgaCode, REGMASK_GAIN_PGAGAIN0); - this->pgaGain[0] = pga; - return true; - } - else if (channel == 1) - { - writeRegisterMasked(REG_GAIN1, pgaCode << 4, REGMASK_GAIN_PGAGAIN1); - this->pgaGain[1] = pga; - return true; - } - else if (channel == 2) - { - writeRegisterMasked(REG_GAIN1, pgaCode << 8, REGMASK_GAIN_PGAGAIN2); - this->pgaGain[2] = pga; - return true; - } - else if (channel == 3) - { - writeRegisterMasked(REG_GAIN1, pgaCode << 12, REGMASK_GAIN_PGAGAIN3); - this->pgaGain[3] = pga; - return true; - } - if (channel == 4) - { - writeRegisterMasked(REG_GAIN2, pgaCode, REGMASK_GAIN_PGAGAIN4); - this->pgaGain[4] = pga; - return true; - } - else if (channel == 5) - { - writeRegisterMasked(REG_GAIN2, pgaCode << 4, REGMASK_GAIN_PGAGAIN5); - this->pgaGain[5] = pga; - return true; - } - else if (channel == 6) - { - writeRegisterMasked(REG_GAIN2, pgaCode << 8, REGMASK_GAIN_PGAGAIN6); - this->pgaGain[6] = pga; - return true; - } - else if (channel == 7) - { - writeRegisterMasked(REG_GAIN2, pgaCode << 12, REGMASK_GAIN_PGAGAIN7); - this->pgaGain[7] = pga; - return true; - } - return false; -} - -ADS131M08_PgaGain ADS131M08Hub::getChannelPGA(uint8_t channel) -{ - if(channel > 7) - { - return ADS131M08_PgaGain::PGA_INVALID; - } - return this->pgaGain[channel]; -} - -void ADS131M08Hub::setGlobalChop(uint16_t global_chop) -{ - writeRegisterMasked(REG_CFG, global_chop << 8, REGMASK_CFG_GC_EN); -} - -void ADS131M08Hub::setGlobalChopDelay(uint16_t delay) -{ - writeRegisterMasked(REG_CFG, delay << 9, REGMASK_CFG_GC_DLY); -} - -bool ADS131M08Hub::setInputChannelSelection(uint8_t channel, uint8_t input) -{ - if (channel > 3) - { - return false; - } - if (channel == 0) - { - writeRegisterMasked(REG_CH0_CFG, input, REGMASK_CHX_CFG_MUX); - return true; - } - else if (channel == 1) - { - writeRegisterMasked(REG_CH1_CFG, input, REGMASK_CHX_CFG_MUX); - return true; - } - else if (channel == 2) - { - writeRegisterMasked(REG_CH2_CFG, input, REGMASK_CHX_CFG_MUX); - return true; - } - else if (channel == 3) - { - writeRegisterMasked(REG_CH3_CFG, input, REGMASK_CHX_CFG_MUX); - return true; - } - else if (channel == 4) - { - writeRegisterMasked(REG_CH4_CFG, input, REGMASK_CHX_CFG_MUX); - return true; - } - else if (channel == 5) - { - writeRegisterMasked(REG_CH5_CFG, input, REGMASK_CHX_CFG_MUX); - return true; - } - else if (channel == 6) - { - writeRegisterMasked(REG_CH6_CFG, input, REGMASK_CHX_CFG_MUX); - return true; - } - else if (channel == 7) - { - writeRegisterMasked(REG_CH7_CFG, input, REGMASK_CHX_CFG_MUX); - return true; - } - return false; -} - -bool ADS131M08Hub::setChannelOffsetCalibration(uint8_t channel, int32_t offset) -{ - - uint16_t MSB = offset >> 8; - uint8_t LSB = offset; - - if (channel > 7) - { - return false; - } - if (channel == 0) - { - writeRegisterMasked(REG_CH0_OCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH0_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); - return true; - } - else if (channel == 1) - { - writeRegisterMasked(REG_CH1_OCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH1_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); - return true; - } - else if (channel == 2) - { - writeRegisterMasked(REG_CH2_OCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH2_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); - return true; - } - else if (channel == 3) - { - writeRegisterMasked(REG_CH3_OCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH3_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); - return true; - } - else if (channel == 4) - { - writeRegisterMasked(REG_CH4_OCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH4_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); - return true; - } - else if (channel == 5) - { - writeRegisterMasked(REG_CH5_OCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH5_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); - return true; - } - else if (channel == 6) - { - writeRegisterMasked(REG_CH6_OCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH6_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); - return true; - } - else if (channel == 7) - { - writeRegisterMasked(REG_CH7_OCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH7_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); - return true; - } - return false; -} - -bool ADS131M08Hub::setChannelGainCalibration(uint8_t channel, uint32_t gain) -{ - - uint16_t MSB = gain >> 8; - uint8_t LSB = gain; - - if (channel > 7) - { - return false; - } - if (channel == 0) - { - writeRegisterMasked(REG_CH0_GCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH0_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); - return true; - } - else if (channel == 1) - { - writeRegisterMasked(REG_CH1_GCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH1_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); - return true; - } - else if (channel == 2) - { - writeRegisterMasked(REG_CH2_GCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH2_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); - return true; - } - else if (channel == 3) - { - writeRegisterMasked(REG_CH3_GCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH3_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); - return true; - } - else if (channel == 4) - { - writeRegisterMasked(REG_CH4_GCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH4_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); - return true; - } - else if (channel == 5) - { - writeRegisterMasked(REG_CH5_GCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH5_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); - return true; - } - else if (channel == 6) - { - writeRegisterMasked(REG_CH6_GCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH6_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); - return true; - } - else if (channel == 7) - { - writeRegisterMasked(REG_CH7_GCAL_MSB, MSB, 0xFFFF); - writeRegisterMasked(REG_CH7_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); - return true; - } - return false; -} - -bool ADS131M08Hub::isDataReady() -{ - if (digitalRead(drdyPin) == HIGH) - { - return false; - } - return true; -} - -uint16_t ADS131M08Hub::getId() -{ - return readRegister(REG_ID); -} - -uint16_t ADS131M08Hub::getModeReg() -{ - return readRegister(REG_MODE); -} - -uint16_t ADS131M08Hub::getClockReg() -{ - return readRegister(REG_CLOCK); -} - -uint16_t ADS131M08Hub::getCfgReg() -{ - return readRegister(REG_CFG); -} - -AdcOutput ADS131M08Hub::readAdcRaw(void) -{ - uint8_t x = 0; - uint8_t x2 = 0; - uint8_t x3 = 0; - int32_t aux; - AdcOutput res; - - digitalWrite(csPin, LOW); - delayMicroseconds(1); - - x = spi.transfer(0x00); - x2 = spi.transfer(0x00); - spi.transfer(0x00); - - this->resultRaw.status = ((x << 8) | x2); - - for(int i = 0; i<8; i++) - { - x = spi.transfer(0x00); - x2 = spi.transfer(0x00); - x3 = spi.transfer(0x00); - - aux = (((x << 16) | (x2 << 8) | x3) & 0x00FFFFFF); - if (aux > 0x7FFFFF) - { - this->resultRaw.ch[i].i = ((~(aux)&0x00FFFFFF) + 1) * -1; - } - else - { - this->resultRaw.ch[i].i = aux; - } - } - - delayMicroseconds(1); - digitalWrite(csPin, HIGH); - - return this->resultRaw; -} - -float ADS131M08Hub::scaleResult(uint8_t num) -{ - if( num >= 8) { - return 0.0; - } - - return this->resultFloat.ch[num].f = (float)(this->resultRaw.ch[num].i * rawToVolts * this->fullScale.ch[num].f); -} - -AdcOutput ADS131M08Hub::scaleResult(void) -{ - // update status - this->resultFloat.status = this->resultRaw.status; - // Scale all channels - for(int i = 0; i<8; i++) - { - this->scaleResult(i); - } - - return this->resultFloat; -} - -AdcOutput ADS131M08Hub::readAdcFloat(void) -{ - this->readAdcRaw(); - return this->scaleResult(); -} -// end of from tpcorrea -void ADS131M08Hub::dump_config() -{ - ESP_LOGCONFIG(TAG, "ADS131M08:"); - LOG_PIN(" CS Pin:", this->cs_); - LOG_PIN(" DRDY Pin:", this->drdy_pin_); - ESP_LOGCONFIG(TAG, " Reference Voltage: %.2fV", this->reference_voltage_); -} - -} // namespace ads131m08 +#include "ads131m08.h" + +namespace esphome { +namespace ads131m08 { + +static const char *const TAG = "ads131m08"; + + +void ADS131M08Hub::setup() +{ + // Initialize SPI with correct settings for ADS131M08 + // SPI mode 1: CPOL=0, CPHA=1 + this->spi_setup(); + // not sure if next few lines are needed here or is it handled in spi_setup() + SPI.begin(); + SPI.setDataMode(SPI_MODE1); + SPI.setBitOrder(MSBFIRST); + SPI.setClockDivider(SPI_CLOCK_DIV8); // Adjust clock speed as needed + this->drdy_pin_->setup(); + this->drdy_pin_->pin_mode(esphome::gpio::FLAG_INPUT | esphome::gpio::FLAG_PULLUP); + this->drdy_pin_->attach_interrupt(&ADS131M08Hub::isr, this, gpio::INTERRUPT_FALLING_EDGE); + this->initialize_ads131m08(); +} + +void ADS131M08Hub::initialize_ads131m08() +{ + // Send RESET command + SPI.transfer(0x06); + delay(1); + + // Send UNLOCK command + SPI.transfer(0x55); + SPI.transfer(0x55); + + // Configure registers as needed (example: set gain, etc.) + // Write to MODE register for continuous conversion, disable internal reference (use external MAX6070AAUT12+T at 1.25V) + write_register(0x02, 0x0000); // MODE register, continuous mode, INTREF_EN = 0 + + // Wait for external reference to settle + delay(100); + + // Start conversions + SPI.transfer(0x08); // START command +} + +void ADS131M08Hub::write_register(uint8_t reg, uint16_t value) +{ + SPI.transfer(0x40 | reg); // WREG command + SPI.transfer(0x00); // Number of registers - 1 (0 for one register) + SPI.transfer((value >> 8) & 0xFF); + SPI.transfer(value & 0xFF); +} + +void IRAM_ATTR ADS131M08Hub::isr(ADS131M08Hub *arg) +{ + arg->txf_init(); // implementing datasheet recommended TXF init in ISR + arg->data_ready_ = true; +} + +void ADS131M08Hub::loop() +{ + if (this->data_ready_) { + this->data_ready_ = false; + this->read_data_(); + } +} + +// ********************** from datasheet ************************ +void ADS131M08Hub::txf_init() +{ + if (firstRead) { + // Clear the ADC's 2-deep FIFO on the first read + for (int i = 0; i sensors_[ch] != nullptr) { + int offset = ch * 3; + int32_t raw = (data_buffer_[offset] << 16) | (data_buffer_[offset + 1] << 8) | data_buffer_[offset + 2]; + if (raw & 0x800000) + raw |= 0xFF000000; // Sign extend + float v = (raw / 8388608.0) * this->reference_voltage_; // 2^23 = 8388608, Vref = 1.25V (MAX6070AAUT12+T) + this->sensors_[ch]->publish_state(v); + } + } +} +*/ +void ADS131M08Hub::read_data_() +{ + this->enable(); + // ADS131M08 Frame: 1 Status Word + 8 Channel Words + 1 CRC Word (24-bit words) + uint8_t frame[30]; // 10 words * 3 bytes + this->read_array(frame, 30); + this->disable(); + + for (int i = 0; i < 8; i++) { + if (this->sensors_[i] != nullptr) { + // Convert 24-bit two's complement to float (Simplified) + int32_t raw = (frame[3+(i*3)] << 16) | (frame[4+(i*3)] << 8) | frame[5+(i*3)]; + if (raw & 0x800000) + raw |= 0xFF000000; // Sign extend + this->sensors_[i]->publish_state(raw * (this->reference_voltage_ / 8388608.0)); // 2^23 = 8388608, Vref = 1.25V ( for MAX6070AAUT12+T ) + } + } +} + +// =============== from tpcorrea ================= +ADS131M08Hub::ADS131M08Hub() : csPin(0), drdyPin(0), clkPin(0), misoPin(0), mosiPin(0), resetPin(0) +{ + for( uint16_t i = 0U; i < 8; i++){ + fullScale.ch[i].f = 1.2; // +-1.2V + pgaGain[i] = ADS131M08_PgaGain::PGA_1; + resultFloat.ch[i].f = 0.0; + resultRaw.ch[i].u[0] = 0U; + resultRaw.ch[i].u[1] = 0U; + } + +} + +uint8_t ADS131M08Hub::writeRegister(uint8_t address, uint16_t value) +{ + uint16_t res; + uint8_t addressRcv; + uint8_t bytesRcv; + uint16_t cmd = 0; + + digitalWrite(csPin, LOW); + delayMicroseconds(1); + + cmd = (CMD_WRITE_REG) | (address << 7) | 0; + + //res = spi.transfer16(cmd); + spi.transfer16(cmd); + spi.transfer(0x00); + + spi.transfer16(value); + spi.transfer(0x00); + + for(int i = 0; i < 8; i++) + { + spi.transfer16(0x0000); + spi.transfer(0x00); + } + + res = spi.transfer16(0x0000); + spi.transfer(0x00); + + for(int i = 0; i < 9; i++) + { + spi.transfer16(0x0000); + spi.transfer(0x00); + } + + delayMicroseconds(1); + digitalWrite(csPin, HIGH); + + addressRcv = (res & REGMASK_CMD_READ_REG_ADDRESS) >> 7; + bytesRcv = (res & REGMASK_CMD_READ_REG_BYTES); + + if (addressRcv == address) + { + return bytesRcv + 1; + } + return 0; +} + +void ADS131M08Hub::writeRegisterMasked(uint8_t address, uint16_t value, uint16_t mask) +{ + // Escribe un valor en el registro, aplicando la mascara para tocar unicamente los bits necesarios. + // No realiza el corrimiento de bits (shift), hay que pasarle ya el valor corrido a la posicion correcta + + // Leo el contenido actual del registro + uint16_t register_contents = readRegister(address); + + // Cambio bit aa bit la mascara (queda 1 en los bits que no hay que tocar y 0 en los bits a modificar) + // Se realiza un AND co el contenido actual del registro. Quedan "0" en la parte a modificar + register_contents = register_contents & ~mask; + + // se realiza un OR con el valor a cargar en el registro. Ojo, valor debe estar en el posicion (shitf) correcta + register_contents = register_contents | value; + + // Escribo nuevamente el registro + writeRegister(address, register_contents); +} + +uint16_t ADS131M08Hub::readRegister(uint8_t address) +{ + uint16_t cmd; + uint16_t data; + + cmd = CMD_READ_REG | (address << 7 | 0); + + digitalWrite(csPin, LOW); + delayMicroseconds(1); + + //data = spi.transfer16(cmd); + spi.transfer16(cmd); + spi.transfer(0x00); + + for(int i = 0; i < 9; i++) + { + spi.transfer16(0x0000); + spi.transfer(0x00); + } + + data = spi.transfer16(0x0000); + spi.transfer(0x00); + + for(int i = 0; i < 9; i++) + { + spi.transfer16(0x0000); + spi.transfer(0x00); + } + + delayMicroseconds(1); + digitalWrite(csPin, HIGH); + return data; +} + +void ADS131M08Hub::begin(uint8_t clk_pin, uint8_t miso_pin, uint8_t mosi_pin, uint8_t cs_pin, uint8_t drdy_pin, uint8_t reset_pin) +{ + // Set pins up + csPin = cs_pin; + drdyPin = drdy_pin; + clkPin = clk_pin; + misoPin = miso_pin; + mosiPin = mosi_pin; + resetPin = reset_pin; + + spi = SPIClass(mosi_pin, miso_pin, clk_pin, cs_pin); + spi.begin(); + spi.beginTransaction(settings); + // Configure chip select as an output + pinMode(csPin, OUTPUT); + pinMode(resetPin, OUTPUT); + // Configure DRDY as an input + pinMode(drdyPin, INPUT); +} + +int8_t ADS131M08Hub::isDataReadySoft(byte channel) +{ + if (channel == 0) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY0); + } + else if (channel == 1) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY1); + } + else if (channel == 2) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY2); + } + else if (channel == 3) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY3); + } + else if (channel == 4) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY4); + } + else if (channel == 5) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY5); + } + else if (channel == 6) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY6); + } + else if (channel == 7) + { + return (readRegister(REG_STATUS) & REGMASK_STATUS_DRDY7); + } + else + { + return -1; + } +} + +bool ADS131M08Hub::isResetStatus(void) +{ + return (readRegister(REG_STATUS) & REGMASK_STATUS_RESET); +} + +bool ADS131M08Hub::isLockSPI(void) +{ + return (readRegister(REG_STATUS) & REGMASK_STATUS_LOCK); +} + +bool ADS131M08Hub::setDrdyFormat(uint8_t drdyFormat) +{ + if (drdyFormat > 1) + { + return false; + } + else + { + writeRegisterMasked(REG_MODE, drdyFormat, REGMASK_MODE_DRDY_FMT); + return true; + } +} + +bool ADS131M08Hub::setDrdyStateWhenUnavailable(uint8_t drdyState) +{ + if (drdyState > 1) + { + return false; + } + else + { + writeRegisterMasked(REG_MODE, drdyState < 1, REGMASK_MODE_DRDY_HiZ); + return true; + } +} + +bool ADS131M08Hub::setPowerMode(uint8_t powerMode) +{ + if (powerMode > 3) + { + return false; + } + else + { + writeRegisterMasked(REG_CLOCK, powerMode, REGMASK_CLOCK_PWR); + return true; + } +} + +bool ADS131M08Hub::setOsr(uint16_t osr) +{ + if (osr > 7) + { + return false; + } + else + { + writeRegisterMasked(REG_CLOCK, osr << 2 , REGMASK_CLOCK_OSR); + return true; + } +} + +void ADS131M08Hub::setFullScale(uint8_t channel, float scale) +{ + if (channel > 7) { + return; + } + + this->fullScale.ch[channel].f = scale; + +} + +float ADS131M08Hub::getFullScale(uint8_t channel) +{ + if (channel > 7) { + return 0.0; + } + + return this->fullScale.ch[channel].f; + +} + +void ADS131M08Hub::reset() +{ + digitalWrite(this->resetPin, LOW); + delay(10); + digitalWrite(this->resetPin, HIGH); +} + +bool ADS131M08Hub::setChannelEnable(uint8_t channel, uint16_t enable) +{ + if (channel > 7) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_CLOCK, enable << 8, REGMASK_CLOCK_CH0_EN); + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_CLOCK, enable << 9, REGMASK_CLOCK_CH1_EN); + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_CLOCK, enable << 10, REGMASK_CLOCK_CH2_EN); + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH3_EN); + return true; + } + else if (channel == 4) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH4_EN); + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH5_EN); + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH6_EN); + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_CLOCK, enable << 11, REGMASK_CLOCK_CH7_EN); + return true; + } + return false; +} + +bool ADS131M08Hub::setChannelPGA(uint8_t channel, ADS131M08_PgaGain pga) +{ uint16_t pgaCode = (uint16_t) pga; + + if (channel > 7) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_GAIN1, pgaCode, REGMASK_GAIN_PGAGAIN0); + this->pgaGain[0] = pga; + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_GAIN1, pgaCode << 4, REGMASK_GAIN_PGAGAIN1); + this->pgaGain[1] = pga; + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_GAIN1, pgaCode << 8, REGMASK_GAIN_PGAGAIN2); + this->pgaGain[2] = pga; + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_GAIN1, pgaCode << 12, REGMASK_GAIN_PGAGAIN3); + this->pgaGain[3] = pga; + return true; + } + if (channel == 4) + { + writeRegisterMasked(REG_GAIN2, pgaCode, REGMASK_GAIN_PGAGAIN4); + this->pgaGain[4] = pga; + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_GAIN2, pgaCode << 4, REGMASK_GAIN_PGAGAIN5); + this->pgaGain[5] = pga; + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_GAIN2, pgaCode << 8, REGMASK_GAIN_PGAGAIN6); + this->pgaGain[6] = pga; + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_GAIN2, pgaCode << 12, REGMASK_GAIN_PGAGAIN7); + this->pgaGain[7] = pga; + return true; + } + return false; +} + +ADS131M08_PgaGain ADS131M08Hub::getChannelPGA(uint8_t channel) +{ + if(channel > 7) + { + return ADS131M08_PgaGain::PGA_INVALID; + } + return this->pgaGain[channel]; +} + +void ADS131M08Hub::setGlobalChop(uint16_t global_chop) +{ + writeRegisterMasked(REG_CFG, global_chop << 8, REGMASK_CFG_GC_EN); +} + +void ADS131M08Hub::setGlobalChopDelay(uint16_t delay) +{ + writeRegisterMasked(REG_CFG, delay << 9, REGMASK_CFG_GC_DLY); +} + +bool ADS131M08Hub::setInputChannelSelection(uint8_t channel, uint8_t input) +{ + if (channel > 3) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_CH0_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_CH1_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_CH2_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_CH3_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 4) + { + writeRegisterMasked(REG_CH4_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_CH5_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_CH6_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_CH7_CFG, input, REGMASK_CHX_CFG_MUX); + return true; + } + return false; +} + +bool ADS131M08Hub::setChannelOffsetCalibration(uint8_t channel, int32_t offset) +{ + + uint16_t MSB = offset >> 8; + uint8_t LSB = offset; + + if (channel > 7) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_CH0_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH0_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_CH1_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH1_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_CH2_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH2_OCAL_LSB, LSB << 8, REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_CH3_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH3_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 4) + { + writeRegisterMasked(REG_CH4_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH4_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_CH5_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH5_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_CH6_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH6_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_CH7_OCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH7_OCAL_LSB, LSB << 8 , REGMASK_CHX_OCAL0_LSB); + return true; + } + return false; +} + +bool ADS131M08Hub::setChannelGainCalibration(uint8_t channel, uint32_t gain) +{ + + uint16_t MSB = gain >> 8; + uint8_t LSB = gain; + + if (channel > 7) + { + return false; + } + if (channel == 0) + { + writeRegisterMasked(REG_CH0_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH0_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 1) + { + writeRegisterMasked(REG_CH1_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH1_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 2) + { + writeRegisterMasked(REG_CH2_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH2_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 3) + { + writeRegisterMasked(REG_CH3_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH3_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 4) + { + writeRegisterMasked(REG_CH4_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH4_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 5) + { + writeRegisterMasked(REG_CH5_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH5_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 6) + { + writeRegisterMasked(REG_CH6_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH6_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + else if (channel == 7) + { + writeRegisterMasked(REG_CH7_GCAL_MSB, MSB, 0xFFFF); + writeRegisterMasked(REG_CH7_GCAL_LSB, LSB << 8, REGMASK_CHX_GCAL0_LSB); + return true; + } + return false; +} + +bool ADS131M08Hub::isDataReady() +{ + if (digitalRead(drdyPin) == HIGH) + { + return false; + } + return true; +} + +uint16_t ADS131M08Hub::getId() +{ + return readRegister(REG_ID); +} + +uint16_t ADS131M08Hub::getModeReg() +{ + return readRegister(REG_MODE); +} + +uint16_t ADS131M08Hub::getClockReg() +{ + return readRegister(REG_CLOCK); +} + +uint16_t ADS131M08Hub::getCfgReg() +{ + return readRegister(REG_CFG); +} + +AdcOutput ADS131M08Hub::readAdcRaw(void) +{ + uint8_t x = 0; + uint8_t x2 = 0; + uint8_t x3 = 0; + int32_t aux; + AdcOutput res; + + digitalWrite(csPin, LOW); + delayMicroseconds(1); + + x = spi.transfer(0x00); + x2 = spi.transfer(0x00); + spi.transfer(0x00); + + this->resultRaw.status = ((x << 8) | x2); + + for(int i = 0; i<8; i++) + { + x = spi.transfer(0x00); + x2 = spi.transfer(0x00); + x3 = spi.transfer(0x00); + + aux = (((x << 16) | (x2 << 8) | x3) & 0x00FFFFFF); + if (aux > 0x7FFFFF) + { + this->resultRaw.ch[i].i = ((~(aux)&0x00FFFFFF) + 1) * -1; + } + else + { + this->resultRaw.ch[i].i = aux; + } + } + + delayMicroseconds(1); + digitalWrite(csPin, HIGH); + + return this->resultRaw; +} + +float ADS131M08Hub::scaleResult(uint8_t num) +{ + if( num >= 8) { + return 0.0; + } + + return this->resultFloat.ch[num].f = (float)(this->resultRaw.ch[num].i * rawToVolts * this->fullScale.ch[num].f); +} + +AdcOutput ADS131M08Hub::scaleResult(void) +{ + // update status + this->resultFloat.status = this->resultRaw.status; + // Scale all channels + for(int i = 0; i<8; i++) + { + this->scaleResult(i); + } + + return this->resultFloat; +} + +AdcOutput ADS131M08Hub::readAdcFloat(void) +{ + this->readAdcRaw(); + return this->scaleResult(); +} +// end of from tpcorrea +void ADS131M08Hub::dump_config() +{ + ESP_LOGCONFIG(TAG, "ADS131M08:"); + LOG_PIN(" CS Pin:", this->cs_); + LOG_PIN(" DRDY Pin:", this->drdy_pin_); + ESP_LOGCONFIG(TAG, " Reference Voltage: %.2fV", this->reference_voltage_); +} + +} // namespace ads131m08 } // namespace esphome \ No newline at end of file diff --git a/components/ads131m08/ads131m08.h b/components/ads131m08/ads131m08.h index 2c8efc9..a1ed8a6 100644 --- a/components/ads131m08/ads131m08.h +++ b/components/ads131m08/ads131m08.h @@ -1,503 +1,503 @@ -#pragma once -// using external voltage reference - -#include "esphome/core/component.h" -#include "esphome/components/spi/spi.h" -#include "esphome/components/sensor/sensor.h" - -namespace esphome { -namespace ads131m08 { - -typedef union { - - int32_t i; - float f; - uint16_t u[2]; - uint8_t b[4]; -} flex32_t; - - -/* Adc Structure. Ch can be read as int32 or float*/ -struct AdcOutput -{ - uint16_t status; - flex32_t ch[8]; -}; - -enum ADS131M08_DRDY_STATE -{ - DS_LOGIC_HIGH = 0, // DEFAULT - DS_HI_Z = 1 -}; - -enum ADS131M08_POWERMODE -{ - PM_VERY_LOW_POWER = 0, - PM_LOW_POWER = 1, - PM_HIGH_RESOLUTION = 2 // DEFAULT -}; - -enum ADS131M08_PGA_GAIN -{ - PGA_1 = 0, - PGA_2 = 1, - PGA_4 = 2, - PGA_8 = 3, - PGA_16 = 4, - PGA_32 = 5, - PGA_64 = 6, - PGA_128 = 7, - PGA_INVALID -}; - -enum ADS131M08_INPUT_CHANNEL_MUX -{ - ICM_AIN0P_AIN0N = 0, // DEFAULT - ICM_INPUT_SHORTED = 1, - ICM_POSITIVE_DC_TEST_SIGNAL = 2, - ICM_NEGATIVE_DC_TEST_SIGNAL = 3, -}; - -enum ADS131M08_OVERSAMPLING_RATIO -{ - OSR_128 = 0, - OSR_256 = 1, - OSR_512 = 2, - OSR_1024 = 3, // default - OSR_2048 = 4, - OSR_4096 = 5, - OSR_8192 = 6, - OSR_16384 = 7 -}; - -enum ADS131M08_WAIT_TIME -{ - WT_128 = 856, - WT_256 = 1112, - WT_512 = 1624, - WT_1024 = 2648, - WT_2048 = 4696, - WT_4096 = 8792, - WT_8192 = 16984, - WT_16384 = 33368 -}; - -// MODE Register -enum ADS131M08_RESET : uint16_t -{ - MODE_NO_RESET = 0x0000, // DEFAULT - MODE_RESET_HAPPENED = 0x0400 -}; - -enum ADS131M08_CRC_TYPE : uint16_t -{ - CRC_CCITT_16BIT = 0x0000, // DEFAULT - CRC_ANSI_16BIT = 0x0800 -}; - -enum ADS131M08_WORD_LENGTH : uint16_t -{ - WLENGTH_16_BITS = 0x0000, - WLENGTH_24_BITS = 0x0100, // DEFAULT - WLENGTH_32_BITS_LSB_ZERO_PADDING = 0x0200, - WLENGTH_32_BITS_MSB_SIGN_EXTEND = 0x0300 -}; - -enum ADS131M08_TIMEOUT : uint16_t -{ - TIMEOUT_DISABLED = 0x0000, - TIMEOUT_ENABLED = 0x0010 // DEFAULT -}; - -enum ADS131M08_DRDY_SELECTION : uint16_t -{ - DRDY_SEL_MOST_LAGGING = 0x0000, // DEFAULT - DRDY_SEL_LOGICAL_OR = 0x0004, - DRDY_SEL_MOST_LEADING_CHAN = 0x0008, - DRDY_SEL_MOST_LEADING_CHAN = 0x000C -}; -enum ADS131M08_DRDY_FORMAT : uint16_t -{ - DRDY_FMT_LEVEL = 0x0000, // Logic low (default) - DRDY_FMT_PULSE = 0x0001 // Low pulse with a fixed duration -}; -// end of MODE Register - -// GAIN1 Register -enum ADS131M08_GAIN1_CHANNEL_PGA : uint16_t { - PGAGAIN0_1 = 0x0000, // default - PGAGAIN0_2 = 0x0001, - PGAGAIN0_4 = 0x0002, - PGAGAIN0_8 = 0x0003, - PGAGAIN0_16 = 0x0004, - PGAGAIN0_32 = 0x0005, - PGAGAIN0_64 = 0x0006, - PGAGAIN0_128 = 0x0007, - PGAGAIN1_1 = 0x0000, // default - PGAGAIN1_2 = 0x0010, - PGAGAIN1_4 = 0x0020, - PGAGAIN1_8 = 0x0030, - PGAGAIN1_16 = 0x0040, - PGAGAIN1_32 = 0x0050, - PGAGAIN1_64 = 0x0060, - PGAGAIN1_128 = 0x0070, - PGAGAIN2_1 = 0x0000, // default - PGAGAIN2_2 = 0x0100, - PGAGAIN2_4 = 0x0200, - PGAGAIN2_8 = 0x0300, - PGAGAIN2_16 = 0x0400, - PGAGAIN2_32 = 0x0500, - PGAGAIN2_64 = 0x0600, - PGAGAIN2_128 = 0x0700, - PGAGAIN3_1 = 0x0000, // default - PGAGAIN3_2 = 0x1000, - PGAGAIN3_4 = 0x2000, - PGAGAIN3_8 = 0x3000, - PGAGAIN3_16 = 0x4000, - PGAGAIN3_32 = 0x5000, // Set PGA gain to 32 for channel - PGAGAIN3_64 = 0x6000, - PGAGAIN3_128 = 0x7000 -}; -// end of GAIN1 Register - -// GAIN2 Register -enum ADS131M08_GAIN2_CHANNEL_PGA : uint16_t { - PGAGAIN4_1 = 0x0000, // default - PGAGAIN4_2 = 0x0001, - PGAGAIN4_4 = 0x0002, - PGAGAIN4_8 = 0x0003, - PGAGAIN4_16 = 0x0004, - PGAGAIN4_32 = 0x0005, - PGAGAIN4_64 = 0x0006, - PGAGAIN4_128 = 0x0007, - PGAGAIN5_1 = 0x0000, // default - PGAGAIN5_2 = 0x0010, - PGAGAIN5_4 = 0x0020, - PGAGAIN5_8 = 0x0030, - PGAGAIN5_16 = 0x0040, - PGAGAIN5_32 = 0x0050, - PGAGAIN5_64 = 0x0060, - PGAGAIN5_128 = 0x0070, - PGAGAIN6_1 = 0x0000, // default - PGAGAIN6_2 = 0x0100, - PGAGAIN6_4 = 0x0200, - PGAGAIN6_8 = 0x0300, - PGAGAIN6_16 = 0x0400, - PGAGAIN6_32 = 0x0500, - PGAGAIN6_64 = 0x0600, - PGAGAIN6_128 = 0x0700, - PGAGAIN7_1 = 0x0000, // default - PGAGAIN7_2 = 0x1000, - PGAGAIN7_4 = 0x2000, - PGAGAIN7_8 = 0x3000, - PGAGAIN7_16 = 0x4000, - PGAGAIN7_32 = 0x5000, - PGAGAIN7_64 = 0x6000, - PGAGAIN7_128 = 0x7000 -}; -// end of GAIN2 Register - - -// Commands -enum ADS131M08_COMMANDS : uint16_t { - CMD_NULL = 0x0000, // No operation; used to read STATUS register - CMD_RESET = 0x0011, // RESET the device - CMD_STANDBY = 0x0022, // Place the device into standby mode - CMD_WAKEUP = 0x0033, // Wake up device from standby mode to conversion mode - CMD_LOCK = 0x0555, // Lock the interface such that only the NULL, UNLOCK, and RREG commands are valid - CMD_UNLOCK = 0x0655, // Unlock the interface after the interface is locked - CMD_RREG = 0xA000, // Read register command base; number of registers to read added to lower byte; register address to upper byte - CMD_WREG = 0x6000, // Write register command base; number of registers to write added to lower byte; register address to upper byte -}; - -// Responses -enum ADS131M08_RESPONSES : uint16_t { - RSP_RESET_OK = 0xFF28, - RSP_RESET_NOK = 0x0011 -}; - -enum ADS131M08_REG { - REG_ID = 0x00, - REG_STATUS = 0x01, - REG_MODE = 0x02, - REG_CLOCK = 0x03, - REG_GAIN1 = 0x04, - REG_GAIN2 = 0x05, - REG_CFG = 0x06, - REG_THRSHLD_MSB = 0x07, - REG_THRSHLD_LSB = 0x08, - REG_CH0_CFG = 0x09, - REG_CH0_OCAL_MSB = 0x0A, - REG_CH0_OCAL_LSB = 0x0B, - REG_CH0_GCAL_MSB = 0x0C, - REG_CH0_GCAL_LSB = 0x0D, - REG_CH1_CFG = 0x0E, - REG_CH1_OCAL_MSB = 0x0F, - REG_CH1_OCAL_LSB = 0x10, - REG_CH1_GCAL_MSB = 0x11, - REG_CH1_GCAL_LSB = 0x12, - REG_CH2_CFG = 0x13, - REG_CH2_OCAL_MSB= 0x14, - REG_CH2_OCAL_LSB= 0x15, - REG_CH2_GCAL_MSB= 0x16, - REG_CH2_GCAL_LSB= 0x17, - REG_CH3_CFG = 0x18, - REG_CH3_OCAL_MSB= 0x19, - REG_CH3_OCAL_LSB= 0x1A, - REG_CH3_GCAL_MSB= 0x1B, - REG_CH3_GCAL_LSB= 0x1C, - REG_CH4_CFG = 0x1D, - REG_CH4_OCAL_MSB= 0x1E, - REG_CH4_OCAL_LSB= 0x1F, - REG_CH4_GCAL_MSB= 0x20, - REG_CH4_GCAL_LSB= 0x21, - REG_CH5_CFG = 0x22, - REG_CH5_OCAL_MSB= 0x23, - REG_CH5_OCAL_LSB= 0x24, - REG_CH5_GCAL_MSB= 0x25, - REG_CH5_GCAL_LSB= 0x26, - REG_CH6_CFG = 0x27, - REG_CH6_OCAL_MSB= 0x28, - REG_CH6_OCAL_LSB= 0x29, - REG_CH6_GCAL_MSB= 0x2A, - REG_CH6_GCAL_LSB= 0x2B, - REG_CH7_CFG = 0x2C, - REG_CH7_OCAL_MSB= 0x2D, - REG_CH7_OCAL_LSB= 0x2E, - REG_CH7_GCAL_MSB= 0x2F, - REG_CH7_GCAL_LSB= 0x30, - REGMAP_CRC = 0x3E, - }; -// Mask READ_REG -static constexpr uint16_t MASK_CMD_READ_REG_ADDRESS = 0x1F80; -static constexpr uint16_t MASK_CMD_READ_REG_BYTES = 0x007F; - -// Mask Register STATUS -static constexpr uint16_t MASK_STATUS_LOCK = 0x8000; -static constexpr uint16_t MASK_STATUS_RESYNC = 0x4000; -static constexpr uint16_t MASK_STATUS_REGMAP = 0x2000; -static constexpr uint16_t MASK_STATUS_CRC_ERR = 0x1000; -static constexpr uint16_t MASK_STATUS_CRC_TYPE = 0x0800; -static constexpr uint16_t MASK_STATUS_RESET = 0x0400; -static constexpr uint16_t MASK_STATUS_WLENGTH = 0x0300; -static constexpr uint16_t MASK_STATUS_DRDY7 = 0x0080; -static constexpr uint16_t MASK_STATUS_DRDY6 = 0x0040; -static constexpr uint16_t MASK_STATUS_DRDY5 = 0x0020; -static constexpr uint16_t MASK_STATUS_DRDY4 = 0x0010; -static constexpr uint16_t MASK_STATUS_DRDY3 = 0x0008; -static constexpr uint16_t MASK_STATUS_DRDY2 = 0x0004; -static constexpr uint16_t MASK_STATUS_DRDY1 = 0x0002; -static constexpr uint16_t MASK_STATUS_DRDY0 = 0x0001; - -// Mask Register MODE -static constexpr uint16_t MASK_MODE_REG_CRC_EN = 0x2000; -static constexpr uint16_t MASK_MODE_RX_CRC_EN = 0x1000; -static constexpr uint16_t MASK_MODE_CRC_TYPE = 0x0800; -static constexpr uint16_t MASK_MODE_RESET = 0x0400; -static constexpr uint16_t MASK_MODE_WLENGTH = 0x0300; -static constexpr uint16_t MASK_MODE_TIMEOUT = 0x0010; -static constexpr uint16_t MASK_MODE_DRDY_SEL = 0x000C; -static constexpr uint16_t MASK_MODE_DRDY_HiZ = 0x0002; -static constexpr uint16_t MASK_MODE_DRDY_FMT = 0x0001; - -// Mask Register CLOCK -static constexpr uint16_t MASK_CLOCK_CH7_EN = 0x8000; -static constexpr uint16_t MASK_CLOCK_CH6_EN = 0x4000; -static constexpr uint16_t MASK_CLOCK_CH5_EN = 0x2000; -static constexpr uint16_t MASK_CLOCK_CH4_EN = 0x1000; -static constexpr uint16_t MASK_CLOCK_CH3_EN = 0x0800; -static constexpr uint16_t MASK_CLOCK_CH2_EN = 0x0400; -static constexpr uint16_t MASK_CLOCK_CH1_EN = 0x0200; -static constexpr uint16_t MASK_CLOCK_CH0_EN = 0x0100; -static constexpr uint16_t MASK_CLOCK_OSR = 0x001C; -static constexpr uint16_t MASK_CLOCK_PWR = 0x0003; -static constexpr uint32_t MASK_CLOCK_ALL_CH_DISABLE = 0x0000; -static constexpr uint32_t MASK_CLOCK_ALL_CH_ENABLE = 0xFF00; -// Mask Register GAIN -static constexpr uint16_t MASK_GAIN_PGAGAIN7 = 0x7000; -static constexpr uint16_t MASK_GAIN_PGAGAIN6 = 0x0700; -static constexpr uint16_t MASK_GAIN_PGAGAIN5 = 0x0070; -static constexpr uint16_t MASK_GAIN_PGAGAIN4 = 0x0007; -static constexpr uint16_t MASK_GAIN_PGAGAIN3 = 0x7000; -static constexpr uint16_t MASK_GAIN_PGAGAIN2 = 0x0700; -static constexpr uint16_t MASK_GAIN_PGAGAIN1 = 0x0070; -static constexpr uint16_t MASK_GAIN_PGAGAIN0 = 0x0007; - -// Mask Register CFG -static constexpr uint16_t MASK_CFG_GC_DLY = 0x1E00; -static constexpr uint16_t MASK_CFG_GC_EN = 0x0100; -static constexpr uint16_t MASK_CFG_CD_ALLCH = 0x0080; -static constexpr uint16_t MASK_CFG_CD_NUM = 0x0070; -static constexpr uint16_t MASK_CFG_CD_LEN = 0x000E; -static constexpr uint16_t MASK_CFG_CD_EN = 0x0001; - -// Mask Register THRSHLD_MSB - dummy, for completeness -static constexpr uint16_t MASK_THRSHLD_MSB_CD_TH_MSB = 0xFFFF; - -// Mask Register THRSHLD_LSB -static constexpr uint16_t MASK_THRSHLD_LSB_CD_TH_LSB = 0xFF00; -static constexpr uint16_t MASK_THRSHLD_LSB_DCBLOCK = 0x000F; - -// Mask Register CHX_CFG -static constexpr uint16_t MASK_CHX_CFG_PHASE = 0xFFC0; -static constexpr uint16_t MASK_CHX_CFG_DCBLKX_DIS = 0x0004; -static constexpr uint16_t MASK_CHX_CFG_MUX = 0x0003; - -// Mask Register CHX_OCAL_MSB - dummy, for completeness -static constexpr uint16_t MASK_CHX_OCAL_MSB = 0xFFFF; - -// Mask Register CHX_OCAL_LSB -static constexpr uint16_t MASK_CHX_OCAL_LSB = 0xFF00; - -// Mask Register CHX_GCAL_MSB - dummy, for completeness -static constexpr uint16_t MASK_CHX_GCAL_MSB = 0xFFFF; - -// Mask Register CHX_GCAL_LSB -static constexpr uint16_t MASK_CHX_GCAL_LSB = 0xFF00; - -// -------------------------------------------------------------------- - -// Conversion modes -static constexpr uint16_t CONVERSION_MODE_CONT = 0; -static constexpr uint16_t CONVERSION_MODE_SINGLE = 1; - -// Data Format -static constexpr uint16_t DATA_FORMAT_TWO_COMPLEMENT = 0; -static constexpr uint16_t DATA_FORMAT_BINARY = 1; - -// Measure Mode -static constexpr uint8_t MEASURE_UNIPOLAR = 1; -static constexpr uint8_t MEASURE_BIPOLAR = 0; - -// Clock Type -static constexpr uint8_t CLOCK_EXTERNAL = 1; -static constexpr uint8_t CLOCK_INTERNAL = 0; - -// PGA Gain -// static constexpr uint16_t PGA_GAIN_1 = 0; -// static constexpr uint16_t PGA_GAIN_2 = 1; -// static constexpr uint16_t PGA_GAIN_4 = 2; -// static constexpr uint16_t PGA_GAIN_8 = 3; -// static constexpr uint16_t PGA_GAIN_16 = 4; -// static constexpr uint16_t PGA_GAIN_32 = 5; -// static constexpr uint16_t PGA_GAIN_64 = 6; -// static constexpr uint16_t PGA_GAIN_128 = 7; - -// Input Filter -static constexpr uint16_t FILTER_SYNC = 0; -static constexpr uint16_t FILTER_FIR = 2; -static constexpr uint16_t FILTER_FIR_IIR = 3; - -// Data Mode -static constexpr uint8_t DATA_MODE_24BITS = 0; -static constexpr uint8_t DATA_MODE_32BITS = 1; - -// Data Rate -static constexpr uint8_t DATA_RATE_0 = 0; -static constexpr uint8_t DATA_RATE_1 = 1; -static constexpr uint8_t DATA_RATE_2 = 2; -static constexpr uint8_t DATA_RATE_3 = 3; -static constexpr uint8_t DATA_RATE_4 = 4; -static constexpr uint8_t DATA_RATE_5 = 5; -static constexpr uint8_t DATA_RATE_6 = 6; -static constexpr uint8_t DATA_RATE_7 = 7; -static constexpr uint8_t DATA_RATE_8 = 8; -static constexpr uint8_t DATA_RATE_9 = 9; -static constexpr uint8_t DATA_RATE_10 = 10; -static constexpr uint8_t DATA_RATE_11 = 11; -static constexpr uint8_t DATA_RATE_12 = 12; -static constexpr uint8_t DATA_RATE_13 = 13; -static constexpr uint8_t DATA_RATE_14 = 14; -static constexpr uint8_t DATA_RATE_15 = 15; -// Sync Mpdes -static constexpr uint16_t SYNC_CONTINUOUS = 1; -static constexpr uint16_t SYNC_PULSE = 0; - -// DIO Config Mode -static constexpr uint8_t DIO_OUTPUT = 1; -static constexpr uint8_t DIO_INPUT = 0; - -static constexpr uint8_t SPI_MASTER_DUMMY = 0xFF; -static constexpr uint16_t SPI_MASTER_DUMMY16 = 0xFFFF; -static constexpr uint32_t SPI_MASTER_DUMMY32 = 0xFFFFFFFF; - - -// end of from datasheet - -class ADS131M08Sensor : public sensor::Sensor, public Component -{ -}; - -class ADS131M08Hub : public Component, public spi::SPIDevice -{ - public: - // from datasheet pg. 93: - const int numFrameWords = 10; // Number of words in a full ADS131M08 SPI frame - unsigned long spiDummyWord[10 /*numFrameWords*/] = { - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000 - }; // Dummy word frame to write ADC during ADC data reads - bool firstRead = true; // Flag to tell us if we are reading ADC data for the first time - signed long adcData; // Location where DMA will store ADC data in memory, length defined elsewhere - void txf_init(); - bool adcRegisterWrite(unsigned short addrMask, unsigned short data, unsigned char adcWordLength); - void initialize_ads131m08_datasheet(); - // end of from datasheet - - bool setChannelPGA(uint8_t channel, uint8_t pga); - void setup() override; - void loop() override; - void set_drdy_pin(InternalGPIOPin *pin) { drdy_pin_ = pin; } - void register_sensor(int channel, ADS131M08Sensor *s) { sensors_[channel] = s; } - void set_reference_voltage(float reference_voltage) { this->reference_voltage_ = reference_voltage; } - void dump_config() override; - - // from tpcorrea - void begin(uint8_t clk_pin, uint8_t miso_pin, uint8_t mosi_pin, uint8_t cs_pin, uint8_t drdy_pin, uint8_t reset_pin); - int8_t isDataReadySoft(uint8_t channel); - bool isDataReady(void); - bool isResetStatus(void); - bool isLockSPI(void); - bool setDrdyFormat(uint8_t drdyFormat); - bool setDrdyStateWhenUnavailable(uint8_t drdyState); - bool setPowerMode(uint8_t powerMode); - bool setChannelEnable(uint8_t channel, uint16_t enable); - bool setChannelPGA(uint8_t channel, ADS131M08_PGA_GAIN pga); - ADS131M08_PGA_GAIN getChannelPGA(uint8_t channel); - void setGlobalChop(uint16_t global_chop); - void setGlobalChopDelay(uint16_t delay); - bool setInputChannelSelection(uint8_t channel, uint8_t input); - bool setChannelOffsetCalibration(uint8_t channel, int32_t offset); - bool setChannelGainCalibration(uint8_t channel, uint32_t gain); - bool setOsr(uint16_t osr); - void setFullScale(uint8_t channel, float scale); - float getFullScale(uint8_t channel); - void reset(); - uint16_t getId(); - uint16_t getModeReg(); - uint16_t getClockReg(); - uint16_t getCfgReg(); - AdcOutput readAdcRaw(void); - AdcOutput readAdcFloat(void); - - protected: - float reference_voltage_; - InternalGPIOPin *drdy_pin_; - ADS131M08Sensor *sensors_[8] = {nullptr}; - volatile bool data_ready_{false}; - static void isr(ADS131M08Hub *arg); - void read_data_(); - void write_register(uint8_t reg, uint16_t value); - -}; - -} // namespace ads131m08 +#pragma once +// using external voltage reference + +#include "esphome/core/component.h" +#include "esphome/components/spi/spi.h" +#include "esphome/components/sensor/sensor.h" + +namespace esphome { +namespace ads131m08 { + +typedef union { + + int32_t i; + float f; + uint16_t u[2]; + uint8_t b[4]; +} flex32_t; + + +/* Adc Structure. Ch can be read as int32 or float*/ +struct AdcOutput +{ + uint16_t status; + flex32_t ch[8]; +}; + +enum ADS131M08_DRDY_STATE +{ + DS_LOGIC_HIGH = 0, // DEFAULT + DS_HI_Z = 1 +}; + +enum ADS131M08_POWERMODE +{ + PM_VERY_LOW_POWER = 0, + PM_LOW_POWER = 1, + PM_HIGH_RESOLUTION = 2 // DEFAULT +}; + +enum ADS131M08_PGA_GAIN +{ + PGA_1 = 0, + PGA_2 = 1, + PGA_4 = 2, + PGA_8 = 3, + PGA_16 = 4, + PGA_32 = 5, + PGA_64 = 6, + PGA_128 = 7, + PGA_INVALID +}; + +enum ADS131M08_INPUT_CHANNEL_MUX +{ + ICM_AIN0P_AIN0N = 0, // DEFAULT + ICM_INPUT_SHORTED = 1, + ICM_POSITIVE_DC_TEST_SIGNAL = 2, + ICM_NEGATIVE_DC_TEST_SIGNAL = 3, +}; + +enum ADS131M08_OVERSAMPLING_RATIO +{ + OSR_128 = 0, + OSR_256 = 1, + OSR_512 = 2, + OSR_1024 = 3, // default + OSR_2048 = 4, + OSR_4096 = 5, + OSR_8192 = 6, + OSR_16384 = 7 +}; + +enum ADS131M08_WAIT_TIME +{ + WT_128 = 856, + WT_256 = 1112, + WT_512 = 1624, + WT_1024 = 2648, + WT_2048 = 4696, + WT_4096 = 8792, + WT_8192 = 16984, + WT_16384 = 33368 +}; + +// MODE Register +enum ADS131M08_RESET : uint16_t +{ + MODE_NO_RESET = 0x0000, // DEFAULT + MODE_RESET_HAPPENED = 0x0400 +}; + +enum ADS131M08_CRC_TYPE : uint16_t +{ + CRC_CCITT_16BIT = 0x0000, // DEFAULT + CRC_ANSI_16BIT = 0x0800 +}; + +enum ADS131M08_WORD_LENGTH : uint16_t +{ + WLENGTH_16_BITS = 0x0000, + WLENGTH_24_BITS = 0x0100, // DEFAULT + WLENGTH_32_BITS_LSB_ZERO_PADDING = 0x0200, + WLENGTH_32_BITS_MSB_SIGN_EXTEND = 0x0300 +}; + +enum ADS131M08_TIMEOUT : uint16_t +{ + TIMEOUT_DISABLED = 0x0000, + TIMEOUT_ENABLED = 0x0010 // DEFAULT +}; + +enum ADS131M08_DRDY_SELECTION : uint16_t +{ + DRDY_SEL_MOST_LAGGING = 0x0000, // DEFAULT + DRDY_SEL_LOGICAL_OR = 0x0004, + DRDY_SEL_MOST_LEADING_CHAN = 0x0008, + DRDY_SEL_MOST_LEADING_CHAN = 0x000C +}; +enum ADS131M08_DRDY_FORMAT : uint16_t +{ + DRDY_FMT_LEVEL = 0x0000, // Logic low (default) + DRDY_FMT_PULSE = 0x0001 // Low pulse with a fixed duration +}; +// end of MODE Register + +// GAIN1 Register +enum ADS131M08_GAIN1_CHANNEL_PGA : uint16_t { + PGAGAIN0_1 = 0x0000, // default + PGAGAIN0_2 = 0x0001, + PGAGAIN0_4 = 0x0002, + PGAGAIN0_8 = 0x0003, + PGAGAIN0_16 = 0x0004, + PGAGAIN0_32 = 0x0005, + PGAGAIN0_64 = 0x0006, + PGAGAIN0_128 = 0x0007, + PGAGAIN1_1 = 0x0000, // default + PGAGAIN1_2 = 0x0010, + PGAGAIN1_4 = 0x0020, + PGAGAIN1_8 = 0x0030, + PGAGAIN1_16 = 0x0040, + PGAGAIN1_32 = 0x0050, + PGAGAIN1_64 = 0x0060, + PGAGAIN1_128 = 0x0070, + PGAGAIN2_1 = 0x0000, // default + PGAGAIN2_2 = 0x0100, + PGAGAIN2_4 = 0x0200, + PGAGAIN2_8 = 0x0300, + PGAGAIN2_16 = 0x0400, + PGAGAIN2_32 = 0x0500, + PGAGAIN2_64 = 0x0600, + PGAGAIN2_128 = 0x0700, + PGAGAIN3_1 = 0x0000, // default + PGAGAIN3_2 = 0x1000, + PGAGAIN3_4 = 0x2000, + PGAGAIN3_8 = 0x3000, + PGAGAIN3_16 = 0x4000, + PGAGAIN3_32 = 0x5000, // Set PGA gain to 32 for channel + PGAGAIN3_64 = 0x6000, + PGAGAIN3_128 = 0x7000 +}; +// end of GAIN1 Register + +// GAIN2 Register +enum ADS131M08_GAIN2_CHANNEL_PGA : uint16_t { + PGAGAIN4_1 = 0x0000, // default + PGAGAIN4_2 = 0x0001, + PGAGAIN4_4 = 0x0002, + PGAGAIN4_8 = 0x0003, + PGAGAIN4_16 = 0x0004, + PGAGAIN4_32 = 0x0005, + PGAGAIN4_64 = 0x0006, + PGAGAIN4_128 = 0x0007, + PGAGAIN5_1 = 0x0000, // default + PGAGAIN5_2 = 0x0010, + PGAGAIN5_4 = 0x0020, + PGAGAIN5_8 = 0x0030, + PGAGAIN5_16 = 0x0040, + PGAGAIN5_32 = 0x0050, + PGAGAIN5_64 = 0x0060, + PGAGAIN5_128 = 0x0070, + PGAGAIN6_1 = 0x0000, // default + PGAGAIN6_2 = 0x0100, + PGAGAIN6_4 = 0x0200, + PGAGAIN6_8 = 0x0300, + PGAGAIN6_16 = 0x0400, + PGAGAIN6_32 = 0x0500, + PGAGAIN6_64 = 0x0600, + PGAGAIN6_128 = 0x0700, + PGAGAIN7_1 = 0x0000, // default + PGAGAIN7_2 = 0x1000, + PGAGAIN7_4 = 0x2000, + PGAGAIN7_8 = 0x3000, + PGAGAIN7_16 = 0x4000, + PGAGAIN7_32 = 0x5000, + PGAGAIN7_64 = 0x6000, + PGAGAIN7_128 = 0x7000 +}; +// end of GAIN2 Register + + +// Commands +enum ADS131M08_COMMANDS : uint16_t { + CMD_NULL = 0x0000, // No operation; used to read STATUS register + CMD_RESET = 0x0011, // RESET the device + CMD_STANDBY = 0x0022, // Place the device into standby mode + CMD_WAKEUP = 0x0033, // Wake up device from standby mode to conversion mode + CMD_LOCK = 0x0555, // Lock the interface such that only the NULL, UNLOCK, and RREG commands are valid + CMD_UNLOCK = 0x0655, // Unlock the interface after the interface is locked + CMD_RREG = 0xA000, // Read register command base; number of registers to read added to lower byte; register address to upper byte + CMD_WREG = 0x6000, // Write register command base; number of registers to write added to lower byte; register address to upper byte +}; + +// Responses +enum ADS131M08_RESPONSES : uint16_t { + RSP_RESET_OK = 0xFF28, + RSP_RESET_NOK = 0x0011 +}; + +enum ADS131M08_REG { + REG_ID = 0x00, + REG_STATUS = 0x01, + REG_MODE = 0x02, + REG_CLOCK = 0x03, + REG_GAIN1 = 0x04, + REG_GAIN2 = 0x05, + REG_CFG = 0x06, + REG_THRSHLD_MSB = 0x07, + REG_THRSHLD_LSB = 0x08, + REG_CH0_CFG = 0x09, + REG_CH0_OCAL_MSB = 0x0A, + REG_CH0_OCAL_LSB = 0x0B, + REG_CH0_GCAL_MSB = 0x0C, + REG_CH0_GCAL_LSB = 0x0D, + REG_CH1_CFG = 0x0E, + REG_CH1_OCAL_MSB = 0x0F, + REG_CH1_OCAL_LSB = 0x10, + REG_CH1_GCAL_MSB = 0x11, + REG_CH1_GCAL_LSB = 0x12, + REG_CH2_CFG = 0x13, + REG_CH2_OCAL_MSB= 0x14, + REG_CH2_OCAL_LSB= 0x15, + REG_CH2_GCAL_MSB= 0x16, + REG_CH2_GCAL_LSB= 0x17, + REG_CH3_CFG = 0x18, + REG_CH3_OCAL_MSB= 0x19, + REG_CH3_OCAL_LSB= 0x1A, + REG_CH3_GCAL_MSB= 0x1B, + REG_CH3_GCAL_LSB= 0x1C, + REG_CH4_CFG = 0x1D, + REG_CH4_OCAL_MSB= 0x1E, + REG_CH4_OCAL_LSB= 0x1F, + REG_CH4_GCAL_MSB= 0x20, + REG_CH4_GCAL_LSB= 0x21, + REG_CH5_CFG = 0x22, + REG_CH5_OCAL_MSB= 0x23, + REG_CH5_OCAL_LSB= 0x24, + REG_CH5_GCAL_MSB= 0x25, + REG_CH5_GCAL_LSB= 0x26, + REG_CH6_CFG = 0x27, + REG_CH6_OCAL_MSB= 0x28, + REG_CH6_OCAL_LSB= 0x29, + REG_CH6_GCAL_MSB= 0x2A, + REG_CH6_GCAL_LSB= 0x2B, + REG_CH7_CFG = 0x2C, + REG_CH7_OCAL_MSB= 0x2D, + REG_CH7_OCAL_LSB= 0x2E, + REG_CH7_GCAL_MSB= 0x2F, + REG_CH7_GCAL_LSB= 0x30, + REGMAP_CRC = 0x3E, + }; +// Mask READ_REG +static constexpr uint16_t MASK_CMD_READ_REG_ADDRESS = 0x1F80; +static constexpr uint16_t MASK_CMD_READ_REG_BYTES = 0x007F; + +// Mask Register STATUS +static constexpr uint16_t MASK_STATUS_LOCK = 0x8000; +static constexpr uint16_t MASK_STATUS_RESYNC = 0x4000; +static constexpr uint16_t MASK_STATUS_REGMAP = 0x2000; +static constexpr uint16_t MASK_STATUS_CRC_ERR = 0x1000; +static constexpr uint16_t MASK_STATUS_CRC_TYPE = 0x0800; +static constexpr uint16_t MASK_STATUS_RESET = 0x0400; +static constexpr uint16_t MASK_STATUS_WLENGTH = 0x0300; +static constexpr uint16_t MASK_STATUS_DRDY7 = 0x0080; +static constexpr uint16_t MASK_STATUS_DRDY6 = 0x0040; +static constexpr uint16_t MASK_STATUS_DRDY5 = 0x0020; +static constexpr uint16_t MASK_STATUS_DRDY4 = 0x0010; +static constexpr uint16_t MASK_STATUS_DRDY3 = 0x0008; +static constexpr uint16_t MASK_STATUS_DRDY2 = 0x0004; +static constexpr uint16_t MASK_STATUS_DRDY1 = 0x0002; +static constexpr uint16_t MASK_STATUS_DRDY0 = 0x0001; + +// Mask Register MODE +static constexpr uint16_t MASK_MODE_REG_CRC_EN = 0x2000; +static constexpr uint16_t MASK_MODE_RX_CRC_EN = 0x1000; +static constexpr uint16_t MASK_MODE_CRC_TYPE = 0x0800; +static constexpr uint16_t MASK_MODE_RESET = 0x0400; +static constexpr uint16_t MASK_MODE_WLENGTH = 0x0300; +static constexpr uint16_t MASK_MODE_TIMEOUT = 0x0010; +static constexpr uint16_t MASK_MODE_DRDY_SEL = 0x000C; +static constexpr uint16_t MASK_MODE_DRDY_HiZ = 0x0002; +static constexpr uint16_t MASK_MODE_DRDY_FMT = 0x0001; + +// Mask Register CLOCK +static constexpr uint16_t MASK_CLOCK_CH7_EN = 0x8000; +static constexpr uint16_t MASK_CLOCK_CH6_EN = 0x4000; +static constexpr uint16_t MASK_CLOCK_CH5_EN = 0x2000; +static constexpr uint16_t MASK_CLOCK_CH4_EN = 0x1000; +static constexpr uint16_t MASK_CLOCK_CH3_EN = 0x0800; +static constexpr uint16_t MASK_CLOCK_CH2_EN = 0x0400; +static constexpr uint16_t MASK_CLOCK_CH1_EN = 0x0200; +static constexpr uint16_t MASK_CLOCK_CH0_EN = 0x0100; +static constexpr uint16_t MASK_CLOCK_OSR = 0x001C; +static constexpr uint16_t MASK_CLOCK_PWR = 0x0003; +static constexpr uint32_t MASK_CLOCK_ALL_CH_DISABLE = 0x0000; +static constexpr uint32_t MASK_CLOCK_ALL_CH_ENABLE = 0xFF00; +// Mask Register GAIN +static constexpr uint16_t MASK_GAIN_PGAGAIN7 = 0x7000; +static constexpr uint16_t MASK_GAIN_PGAGAIN6 = 0x0700; +static constexpr uint16_t MASK_GAIN_PGAGAIN5 = 0x0070; +static constexpr uint16_t MASK_GAIN_PGAGAIN4 = 0x0007; +static constexpr uint16_t MASK_GAIN_PGAGAIN3 = 0x7000; +static constexpr uint16_t MASK_GAIN_PGAGAIN2 = 0x0700; +static constexpr uint16_t MASK_GAIN_PGAGAIN1 = 0x0070; +static constexpr uint16_t MASK_GAIN_PGAGAIN0 = 0x0007; + +// Mask Register CFG +static constexpr uint16_t MASK_CFG_GC_DLY = 0x1E00; +static constexpr uint16_t MASK_CFG_GC_EN = 0x0100; +static constexpr uint16_t MASK_CFG_CD_ALLCH = 0x0080; +static constexpr uint16_t MASK_CFG_CD_NUM = 0x0070; +static constexpr uint16_t MASK_CFG_CD_LEN = 0x000E; +static constexpr uint16_t MASK_CFG_CD_EN = 0x0001; + +// Mask Register THRSHLD_MSB - dummy, for completeness +static constexpr uint16_t MASK_THRSHLD_MSB_CD_TH_MSB = 0xFFFF; + +// Mask Register THRSHLD_LSB +static constexpr uint16_t MASK_THRSHLD_LSB_CD_TH_LSB = 0xFF00; +static constexpr uint16_t MASK_THRSHLD_LSB_DCBLOCK = 0x000F; + +// Mask Register CHX_CFG +static constexpr uint16_t MASK_CHX_CFG_PHASE = 0xFFC0; +static constexpr uint16_t MASK_CHX_CFG_DCBLKX_DIS = 0x0004; +static constexpr uint16_t MASK_CHX_CFG_MUX = 0x0003; + +// Mask Register CHX_OCAL_MSB - dummy, for completeness +static constexpr uint16_t MASK_CHX_OCAL_MSB = 0xFFFF; + +// Mask Register CHX_OCAL_LSB +static constexpr uint16_t MASK_CHX_OCAL_LSB = 0xFF00; + +// Mask Register CHX_GCAL_MSB - dummy, for completeness +static constexpr uint16_t MASK_CHX_GCAL_MSB = 0xFFFF; + +// Mask Register CHX_GCAL_LSB +static constexpr uint16_t MASK_CHX_GCAL_LSB = 0xFF00; + +// -------------------------------------------------------------------- + +// Conversion modes +static constexpr uint16_t CONVERSION_MODE_CONT = 0; +static constexpr uint16_t CONVERSION_MODE_SINGLE = 1; + +// Data Format +static constexpr uint16_t DATA_FORMAT_TWO_COMPLEMENT = 0; +static constexpr uint16_t DATA_FORMAT_BINARY = 1; + +// Measure Mode +static constexpr uint8_t MEASURE_UNIPOLAR = 1; +static constexpr uint8_t MEASURE_BIPOLAR = 0; + +// Clock Type +static constexpr uint8_t CLOCK_EXTERNAL = 1; +static constexpr uint8_t CLOCK_INTERNAL = 0; + +// PGA Gain +// static constexpr uint16_t PGA_GAIN_1 = 0; +// static constexpr uint16_t PGA_GAIN_2 = 1; +// static constexpr uint16_t PGA_GAIN_4 = 2; +// static constexpr uint16_t PGA_GAIN_8 = 3; +// static constexpr uint16_t PGA_GAIN_16 = 4; +// static constexpr uint16_t PGA_GAIN_32 = 5; +// static constexpr uint16_t PGA_GAIN_64 = 6; +// static constexpr uint16_t PGA_GAIN_128 = 7; + +// Input Filter +static constexpr uint16_t FILTER_SYNC = 0; +static constexpr uint16_t FILTER_FIR = 2; +static constexpr uint16_t FILTER_FIR_IIR = 3; + +// Data Mode +static constexpr uint8_t DATA_MODE_24BITS = 0; +static constexpr uint8_t DATA_MODE_32BITS = 1; + +// Data Rate +static constexpr uint8_t DATA_RATE_0 = 0; +static constexpr uint8_t DATA_RATE_1 = 1; +static constexpr uint8_t DATA_RATE_2 = 2; +static constexpr uint8_t DATA_RATE_3 = 3; +static constexpr uint8_t DATA_RATE_4 = 4; +static constexpr uint8_t DATA_RATE_5 = 5; +static constexpr uint8_t DATA_RATE_6 = 6; +static constexpr uint8_t DATA_RATE_7 = 7; +static constexpr uint8_t DATA_RATE_8 = 8; +static constexpr uint8_t DATA_RATE_9 = 9; +static constexpr uint8_t DATA_RATE_10 = 10; +static constexpr uint8_t DATA_RATE_11 = 11; +static constexpr uint8_t DATA_RATE_12 = 12; +static constexpr uint8_t DATA_RATE_13 = 13; +static constexpr uint8_t DATA_RATE_14 = 14; +static constexpr uint8_t DATA_RATE_15 = 15; +// Sync Mpdes +static constexpr uint16_t SYNC_CONTINUOUS = 1; +static constexpr uint16_t SYNC_PULSE = 0; + +// DIO Config Mode +static constexpr uint8_t DIO_OUTPUT = 1; +static constexpr uint8_t DIO_INPUT = 0; + +static constexpr uint8_t SPI_MASTER_DUMMY = 0xFF; +static constexpr uint16_t SPI_MASTER_DUMMY16 = 0xFFFF; +static constexpr uint32_t SPI_MASTER_DUMMY32 = 0xFFFFFFFF; + + +// end of from datasheet + +class ADS131M08Sensor : public sensor::Sensor, public Component +{ +}; + +class ADS131M08Hub : public Component, public spi::SPIDevice +{ + public: + // from datasheet pg. 93: + const int numFrameWords = 10; // Number of words in a full ADS131M08 SPI frame + unsigned long spiDummyWord[10 /*numFrameWords*/] = { + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 + }; // Dummy word frame to write ADC during ADC data reads + bool firstRead = true; // Flag to tell us if we are reading ADC data for the first time + signed long adcData; // Location where DMA will store ADC data in memory, length defined elsewhere + void txf_init(); + bool adcRegisterWrite(unsigned short addrMask, unsigned short data, unsigned char adcWordLength); + void initialize_ads131m08_datasheet(); + // end of from datasheet + + bool setChannelPGA(uint8_t channel, uint8_t pga); + void setup() override; + void loop() override; + void set_drdy_pin(InternalGPIOPin *pin) { drdy_pin_ = pin; } + void register_sensor(int channel, ADS131M08Sensor *s) { sensors_[channel] = s; } + void set_reference_voltage(float reference_voltage) { this->reference_voltage_ = reference_voltage; } + void dump_config() override; + + // from tpcorrea + void begin(uint8_t clk_pin, uint8_t miso_pin, uint8_t mosi_pin, uint8_t cs_pin, uint8_t drdy_pin, uint8_t reset_pin); + int8_t isDataReadySoft(uint8_t channel); + bool isDataReady(void); + bool isResetStatus(void); + bool isLockSPI(void); + bool setDrdyFormat(uint8_t drdyFormat); + bool setDrdyStateWhenUnavailable(uint8_t drdyState); + bool setPowerMode(uint8_t powerMode); + bool setChannelEnable(uint8_t channel, uint16_t enable); + bool setChannelPGA(uint8_t channel, ADS131M08_PGA_GAIN pga); + ADS131M08_PGA_GAIN getChannelPGA(uint8_t channel); + void setGlobalChop(uint16_t global_chop); + void setGlobalChopDelay(uint16_t delay); + bool setInputChannelSelection(uint8_t channel, uint8_t input); + bool setChannelOffsetCalibration(uint8_t channel, int32_t offset); + bool setChannelGainCalibration(uint8_t channel, uint32_t gain); + bool setOsr(uint16_t osr); + void setFullScale(uint8_t channel, float scale); + float getFullScale(uint8_t channel); + void reset(); + uint16_t getId(); + uint16_t getModeReg(); + uint16_t getClockReg(); + uint16_t getCfgReg(); + AdcOutput readAdcRaw(void); + AdcOutput readAdcFloat(void); + + protected: + float reference_voltage_; + InternalGPIOPin *drdy_pin_; + ADS131M08Sensor *sensors_[8] = {nullptr}; + volatile bool data_ready_{false}; + static void isr(ADS131M08Hub *arg); + void read_data_(); + void write_register(uint8_t reg, uint16_t value); + +}; + +} // namespace ads131m08 } // namespace esphome \ No newline at end of file diff --git a/components/ads131m08/sensor.py b/components/ads131m08/sensor.py index 50943cd..8e46586 100644 --- a/components/ads131m08/sensor.py +++ b/components/ads131m08/sensor.py @@ -1,34 +1,34 @@ -import esphome.codegen as cg -import esphome.config_validation as cv -from esphome.components import sensor -from esphome.const import ( - CONF_ID, CONF_CHANNEL, STATE_CLASS_MEASUREMENT, DEVICE_CLASS_VOLTAGE, UNIT_VOLT, ICON_FLASH -) -from . import ADS131M08Hub, ads131m08_ns - -AUTO_LOAD = [ - "sensor", -] - -CONF_ADS131M08_ID = "ads131m08_id" - -ADS131M08Sensor = ads131m08_ns.class_("ADS131M08Sensor", sensor.Sensor, cg.Component) - -CONFIG_SCHEMA = sensor.sensor_schema( - unit_of_measurement=UNIT_VOLT, - device_class=DEVICE_CLASS_VOLTAGE, - icon=ICON_FLASH, - state_class=STATE_CLASS_MEASUREMENT, -).extend({ - cv.GenerateID(): cv.declare_id(ADS131M08Sensor), - cv.Required(CONF_ADS131M08_ID): cv.use_id(ADS131M08Hub), - cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7), -}).extend(cv.COMPONENT_SCHEMA) - -async def to_code(config): - var = cg.new_Pvariable(config[CONF_ID]) - await cg.register_component(var, config) - await sensor.register_sensor(var, config) - - hub = await cg.get_variable(config[CONF_ADS131M08_ID]) +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import sensor +from esphome.const import ( + CONF_ID, CONF_CHANNEL, STATE_CLASS_MEASUREMENT, DEVICE_CLASS_VOLTAGE, UNIT_VOLT, ICON_FLASH +) +from . import ADS131M08Hub, ads131m08_ns + +AUTO_LOAD = [ + "sensor", +] + +CONF_ADS131M08_ID = "ads131m08_id" + +ADS131M08Sensor = ads131m08_ns.class_("ADS131M08Sensor", sensor.Sensor, cg.Component) + +CONFIG_SCHEMA = sensor.sensor_schema( + unit_of_measurement=UNIT_VOLT, + device_class=DEVICE_CLASS_VOLTAGE, + icon=ICON_FLASH, + state_class=STATE_CLASS_MEASUREMENT, +).extend({ + cv.GenerateID(): cv.declare_id(ADS131M08Sensor), + cv.Required(CONF_ADS131M08_ID): cv.use_id(ADS131M08Hub), + cv.Required(CONF_CHANNEL): cv.int_range(min=0, max=7), +}).extend(cv.COMPONENT_SCHEMA) + +async def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + await cg.register_component(var, config) + await sensor.register_sensor(var, config) + + hub = await cg.get_variable(config[CONF_ADS131M08_ID]) cg.add(hub.register_sensor(config[CONF_CHANNEL], var)) \ No newline at end of file diff --git a/images/fire-red.svg b/images/fire-red.svg index a308af1..2b34d6c 100644 --- a/images/fire-red.svg +++ b/images/fire-red.svg @@ -1,14 +1,14 @@ - - - - - - + + + + + + diff --git a/sthome-ut3.yaml b/sthome-ut3.yaml index 00a99fd..66dd441 100644 --- a/sthome-ut3.yaml +++ b/sthome-ut3.yaml @@ -1,6 +1,5 @@ packages: - !include common/wifi.yaml - - !include common/felicityinverter.yaml substitutions: name: sthome-ut3 @@ -9,30 +8,25 @@ substitutions: esphome: name: "${name}" friendly_name: "${friendly_name}" -# on_boot: -# - priority: 600 # This is where most sensors are set up (higher number means higher priority) -# then: -# - uart.write: -# id: inv_uart1 -# data: [0x0D, 0x0A] -# - uart.write: -# id: inv_uart2 -# data: [0x0D, 0x0A] - -#external_components: -# - source: github://pr#8103 -# components: [uart] -# - source: github://pr#8032 -# components: [modbus, modbus_controller] #, growatt_solar] -# refresh: 1h - + includes: + - source # copies folder with files to relevant to be included in esphome compile + - # angle brackets ensure file is included above globals in main.cpp. Make sure to use include GUARDS in the file to prevent double inclusion + - + - + - + - + - + - + globals: - id: geyser_relay_status type: bool restore_value: yes initial_value: 'false' - +debug: + update_interval: 10s + esp32: board: nodemcu-32s #esp32dev framework: @@ -67,34 +61,8 @@ wifi: captive_portal: -uart: - - id: inv_uart1 - rx_pin: GPIO16 - tx_pin: GPIO17 - baud_rate: 2400 - stop_bits: 1 - parity: NONE - debug: - direction: BOTH - dummy_receiver: false - after: - delimiter: "\r" - sequence: - - lambda: UARTDebug::log_hex(direction, bytes, ','); - -# - id: inv_uart2 -# rx_pin: GPIO25 -# tx_pin: GPIO26 -# baud_rate: 2400 -# stop_bits: 1 -# parity: NONE -# debug: -# direction: BOTH -# dummy_receiver: false -# after: -# delimiter: "\r" -# sequence: -# - lambda: UARTDebug::log_hex(direction, bytes, ' '); +#preferences: +# flash_write_interval: 30s sun: id: sun_sensor @@ -103,650 +71,154 @@ sun: time: - platform: homeassistant - id: time_source + +text_sensor: + - platform: debug + device: + name: "Device Info" + reset_reason: + name: "Reset Reason" + + # human readable update text sensor from sensor:uptime + - platform: template + name: Uptime + id: uptime_human + icon: mdi:clock-start + update_interval: 10s switch: - platform: restart name: "${name} Restart" id: "restart_switch" -modbus: - - id: modbus1 - uart_id: inv_uart1 - # flow_control_pin: GPIO4 - send_wait_time: 1200ms #250ms - disable_crc: false - role: server + - platform: gpio + pin: + number: GPIO16 + inverted: true + id: relay1 + name: "Floodlights Backyard" + icon: "mdi:light-flood-down" + restore_mode: RESTORE_DEFAULT_OFF + # the backyard floodlight auto turns off in 4min 14 sec. So we need to switch relay off just before or at this time + # TODO: remove or extend auto turn off to >= 10min + on_turn_on: + - delay: 250s + - switch.turn_off: relay1 -# - id: modbus2 -# uart_id: inv_uart2 -# #flow_control_pin: GPIO27 -# send_wait_time: 1200ms #250ms -# disable_crc: false -# role: server + - platform: gpio + pin: + number: GPIO17 + inverted: true + id: relay2 + name: "Relay 2" + icon: "mdi:run-fast" + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + - delay: 1000ms + - switch.turn_off: relay2 -modbus_controller: -# - id: modbus_device1 -# modbus_id: modbus1 -# address: 0x01 -# allow_duplicate_commands: False -# command_throttle: 0ms -# update_interval: 10s #30s -# offline_skip_updates: 2 -# max_cmd_retries: 0 -# setup_priority: -10 -# - id: modbus_device2 -# modbus_id: modbus2 -# address: 0x01 -# allow_duplicate_commands: False -# command_throttle: 0ms -# update_interval: 60s #30s -# offline_skip_updates: 2 -# max_cmd_retries: 0 -# setup_priority: -10 + - platform: gpio + pin: + number: GPIO18 + inverted: true + id: relay3 + name: "Relay 3" + icon: "mdi:run-fast" + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + - delay: 1000ms + - switch.turn_off: relay3 + + - platform: gpio + pin: + number: GPIO19 + inverted: true + id: relay4 + name: "Alarm Zone 4" + icon: "mdi:alarm-light-outline" + restore_mode: RESTORE_DEFAULT_OFF + on_turn_on: + - if: + condition: + - lambda: |- + double sun_elevation = id(sun_sensor).elevation(); + return (sun_elevation <= -6); // -6° = civil twilight, -12° = nautical twilight, -18° = astronomical twilight + #- sun.is_below_horizon: + then: + - switch.turn_on: relay1 + - if: + condition: + - binary_sensor.is_on: floodlight_test + then: + - switch.turn_on: relay1 + - delay: 30s + - switch.turn_off: relay4 - - modbus_id: modbus1 - address: 0x1 - server_registers: - - address: 0x1100 - value_type: U_WORD - read_lambda: |- - return 0x01; - - address: 0x1101 - value_type: U_WORD - read_lambda: |- - return 0x02; // b0=power-on mode/PowerOnMode 1=standby mode/StandbyMode 2=bypass mode/BypassMode 3=battery mode/BatteryMode 4=fault mode/FaultMode 5=mains mode/LineMode 6=charging mode/PVChargeMode 0=no - - address: 0x1102 - value_type: U_WORD - read_lambda: |- - return 0x02; // No charge 1=Constant current charge/Bulk charge 2=Constant voltage charge/Absorption charge 3=Float charge/Float charge - - address: 0x1103 # Fault Code - value_type: U_WORD - read_lambda: |- - return 0x0; - - address: 0x1104 # PowerFlowMsg - value_type: U_WORD - read_lambda: |- - return 0x0; - - address: 0x1105 # dummy - value_type: U_WORD - read_lambda: |- - return 0x0; - - address: 0x1106 # dummy - value_type: U_DWORD - read_lambda: |- - return 0x0; - - address: 0x1108 # Battery voltage - value_type: U_WORD - read_lambda: |- - return 0x3A; - - address: 0x1109 # Battery current - value_type: S_WORD - read_lambda: |- - return 0xFFC4; // -60A - - address: 0x110A # Battery power - value_type: S_WORD - read_lambda: |- - return 0xED40; // -4800W - - address: 0x110B # dummy - value_type: U_QWORD - read_lambda: |- - return 0; - - address: 0x110F # dummy - value_type: U_DWORD - read_lambda: |- - return 0; - - address: 0x1111 # AC Output voltage - value_type: U_WORD - read_lambda: |- - return 0xE7; // 231V - - address: 0x1112 # dummy - value_type: U_QWORD - read_lambda: |- - return 0; - - address: 0x1116 # dummy - value_type: U_WORD - read_lambda: |- - return 0; - - address: 0x1117 # AC Input voltage - value_type: U_WORD - read_lambda: |- - return 0xE6; // 230V - - address: 0x1118 # dummy - value_type: U_WORD - read_lambda: |- - return 0; - - address: 0x1119 # AC Input frequency - value_type: U_WORD - read_lambda: |- - return 50; // 50Hz - - address: 0x111A # dummy - value_type: U_QWORD - read_lambda: |- - return 0; - - address: 0x111B # dummy - value_type: U_WORD - read_lambda: |- - return 0; - - address: 0x111C # dummy - value_type: U_DWORD - read_lambda: |- - return 0; - - address: 0x111E - value_type: S_WORD - read_lambda: |- - return 100; // 100W - - address: 0x111F - value_type: U_WORD - read_lambda: |- - return 120; // 120VA - - address: 0x1120 - value_type: U_WORD - read_lambda: |- - return 50; // 50% - - address: 0x1121 # dummy - value_type: U_QWORD - read_lambda: |- - return 0; - - address: 0x1125 # dummy - value_type: U_WORD - read_lambda: |- - return 0; - - address: 0x1126 - value_type: U_WORD - read_lambda: |- - return 450; // 450V - - address: 0x1127 # dummy - value_type: U_WORD - read_lambda: |- - return 0; - - address: 0x1128 # dummy - value_type: U_DWORD - read_lambda: |- - return 0; - - address: 0x112A - value_type: S_WORD - read_lambda: |- - return 4812; // 4812W -# - modbus_id: modbus2 -# server_registers: -# - address: 0x1100 -# value_type: U_WORD -# read_lambda: |- -# return 0x01; -# - address: 0x1101 -# value_type: U_WORD -# read_lambda: |- -# return 0x02; // b0=power-on mode/PowerOnMode 1=standby mode/StandbyMode 2=bypass mode/BypassMode 3=battery mode/BatteryMode 4=fault mode/FaultMode 5=mains mode/LineMode 6=charging mode/PVChargeMode 0=no -# - address: 0x1102 -# value_type: U_WORD -# read_lambda: |- -# return 0x02; // No charge 1=Constant current charge/Bulk charge 2=Constant voltage charge/Absorption charge 3=Float charge/Float charge -# - address: 0x1103 # Fault Code -# value_type: U_WORD -# read_lambda: |- -# return 0x0; -# - address: 0x1104 # PowerFlowMsg -# value_type: U_WORD -# read_lambda: |- -# return 0x0; -# - address: 0x1105 # dummy -# value_type: U_WORD -# read_lambda: |- -# return 0x0; -# - address: 0x1106 # dummy -# value_type: U_DWORD -# read_lambda: |- -# return 0x0; -# - address: 0x1108 # Battery voltage -# value_type: U_WORD -# read_lambda: |- -# return 0x3A; -# - address: 0x1109 # Battery current -# value_type: S_WORD -# read_lambda: |- -# return 0xFFC4; // -60A -# - address: 0x110A # Battery power -# value_type: S_WORD -# read_lambda: |- -# return 0xED40; // -4800W -# - address: 0x110B # dummy -# value_type: U_QWORD -# read_lambda: |- -# return 0; -# - address: 0x110F # dummy -# value_type: U_DWORD -# read_lambda: |- -# return 0; -# - address: 0x1111 # AC Output voltage -# value_type: U_WORD -# read_lambda: |- -# return 0xE7; // 231V -# - address: 0x1112 # dummy -# value_type: U_QWORD -# read_lambda: |- -# return 0; -# - address: 0x1116 # dummy -# value_type: U_WORD -# read_lambda: |- -# return 0; -# - address: 0x1117 # AC Input voltage -# value_type: U_WORD -# read_lambda: |- -# return 0xE6; // 230V -# - address: 0x1118 # dummy -# value_type: U_WORD -# read_lambda: |- -# return 0; -# - address: 0x1119 # AC Input frequency -# value_type: U_WORD -# read_lambda: |- -# return 50; // 50Hz -# - address: 0x111A # dummy -# value_type: U_QWORD -# read_lambda: |- -# return 0; -# - address: 0x111B # dummy -# value_type: U_WORD -# read_lambda: |- -# return 0; -# - address: 0x111C # dummy -# value_type: U_DWORD -# read_lambda: |- -# return 0; -# - address: 0x111E -# value_type: S_WORD -# read_lambda: |- -# return 100; // 100W -# - address: 0x111F -# value_type: U_WORD -# read_lambda: |- -# return 120; // 120VA -# - address: 0x1120 -# value_type: U_WORD -# read_lambda: |- -# return 50; // 50% -# - address: 0x1121 # dummy -# value_type: U_QWORD -# read_lambda: |- -# return 0; -# - address: 0x1125 # dummy -# value_type: U_WORD -# read_lambda: |- -# return 0; -# - address: 0x1126 -# value_type: U_WORD -# read_lambda: |- -# return 450; // 450V -# - address: 0x1127 # dummy -# value_type: U_WORD -# read_lambda: |- -# return 0; -# - address: 0x1128 # dummy -# value_type: U_DWORD -# read_lambda: |- -# return 0; -# - address: 0x112A -# value_type: S_WORD -# read_lambda: |- -# return 4812; // 4812W +# define DIGITAL_D1 04 +binary_sensor: + - platform: gpio + # device_class: light + id: floodlight_test + pin: + number: GPIO04 + mode: + input: true + pullup: true + filters: + - delayed_off: 100ms + name: "Floodlights Test Mode" + icon: "mdi:lightbulb-on-outline" + +sensor: + - platform: adc + pin: 35 + name: "Alarm Signal" + id: alarm_signal + update_interval: 2000ms + attenuation: 12db + sampling_mode: avg + filters: + - lambda: + if (x >= 3.11) { + return x * 1.60256; + } else if (x <= 0.25) { + return 0; + } else { + return x * 1.51; + } + on_value: + then: + # switch on floodlights + lambda: |- + if (id(alarm_signal).state > 1.5) { + id(relay1).turn_on(); + } -#text_sensor: -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 SerialNo" -# register_type: holding -# address: ${Felicity_Inv_SerialNo} # 0xF804 -# response_size: 7 -# register_count: 7 -# raw_encode: HEXBYTES -# -##- platform: modbus_controller -## modbus_controller_id: modbus_device2 -## name: "Inverter2 SerialNo" -## register_type: holding -## address: ${Felicity_Inv_SerialNo} # 0xF804 -## response_size: 7 -## register_count: 7 -## raw_encode: HEXBYTES -# -#sensor: -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Type" -# id: inverter1_type -# register_type: holding -# address: ${Felicity_Inv_Type} # 0xF800 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Sub Type" -# register_type: holding -# address: ${Felicity_Inv_SubType} # 0xF801 -# value_type: U_WORD -# register_count: 3 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 CPU1 F/W Version" -# register_type: holding -# address: ${Felicity_Inv_CPU1_FW_Version} # 0xF80B -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 CPU2 F/W Version" -# register_type: holding -# address: ${Felicity_Inv_CPU2_FW_Version} # 0xF80C -# value_type: U_WORD -# register_count: 3 - -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 SettingDataSn" -# register_type: holding -# address: ${Felicity_Inv_SettingDataSn} # 0x1100 -# value_type: U_WORD -# register_count: 1 -## lambda: |- -## if (!isnan(id(inverter1_type).state)) { -## return x; // Update the sensor's value if the condition is true -## } else { -## return NAN; // Return NaN to skip updating if the condition is false -## } -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Working Mode" -# register_type: holding -# address: ${Felicity_Inv_WorkingMode} # 0x1101 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Charge Mode" -# register_type: holding -# address: ${Felicity_Inv_BatteryChargingStage} # 0x1102 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Fault Code" -# register_type: holding -# address: ${Felicity_Inv_FaultCode} # 0x1103 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Power Flow" -# register_type: holding -# address: ${Felicity_Inv_PowerFlowMsg} # 0x1104 -# value_type: U_WORD -# register_count: 4 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Battery Voltage" -# register_type: holding -# address: ${Felicity_Inv_BatteryVoltage} # 0x1108 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Battery Current" -# register_type: holding -# address: ${Felicity_Inv_BatteryCurrent} # 0x1109 -# value_type: S_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 BatteryPower" -# register_type: holding -# address: ${Felicity_Inv_BatteryPower} # 0x110A -# value_type: S_WORD -# register_count: 7 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 AC Output Voltage" -# register_type: holding -# address: ${Felicity_Inv_ACOutputVoltage} # 0x1111 -# value_type: U_WORD -# register_count: 6 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 AC Input Voltage" -# register_type: holding -# address: ${Felicity_Inv_ACInputVoltage} # 0x1117 -# value_type: U_WORD -# register_count: 2 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 AC Input Frequency" -# register_type: holding -# address: ${Felicity_Inv_ACInputFrequency} # 0x1119 -# value_type: U_WORD -# register_count: 5 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 AC Output Active Power" -# register_type: holding -# address: ${Felicity_Inv_ACOutputActivePower} # 0x111E -# value_type: S_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 AC Output Apparent Power" -# register_type: holding -# address: ${Felicity_Inv_ACOutputApparentPower} # 0x111F -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 Load Percentage" -# register_type: holding -# address: ${Felicity_Inv_LoadPercentage} # 0x1120 -# value_type: U_WORD -# register_count: 6 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 PV Input Voltage" -# register_type: holding -# address: ${Felicity_Inv_PVInputVoltage} # 0x1126 -# value_type: U_WORD -# register_count: 4 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device1 -# name: "Inverter1 PV Input Power" -# register_type: holding -# address: ${Felicity_Inv_PVInputPower} # 0x112A -# value_type: S_WORD -# register_count: 1 - - -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Type" -# register_type: holding -# address: ${Felicity_Inv_Type} # 0xF800 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Sub Type" -# register_type: holding -# address: ${Felicity_Inv_SubType} # 0xF801 -# value_type: U_WORD -# register_count: 1 - -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Dummy" -# register_type: holding -# address: 0xF802 -# value_type: U_WORD -# register_count: 2 - -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 CPU1 F/W Version" -# register_type: holding -# address: ${Felicity_Inv_CPU1_FW_Version} # 0xF80B -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 CPU2 F/W Version" -# register_type: holding -# address: ${Felicity_Inv_CPU2_FW_Version} # 0xF80C -# value_type: U_WORD -# register_count: 3 - -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 SettingDataSn" -# register_type: holding -# address: ${Felicity_Inv_SettingDataSn} # 0x1100 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Working Mode" -# register_type: holding -# address: ${Felicity_Inv_WorkingMode} # 0x1101 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Charge Mode" -# register_type: holding -# address: ${Felicity_Inv_BatteryChargingStage} # 0x1102 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Fault Code" -# register_type: holding -# address: ${Felicity_Inv_FaultCode} # 0x1103 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Power Flow" -# register_type: holding -# address: ${Felicity_Inv_PowerFlowMsg} # 0x1104 -# value_type: U_WORD -# register_count: 4 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Battery Voltage" -# register_type: holding -# address: ${Felicity_Inv_BatteryVoltage} # 0x1108 -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Battery Current" -# register_type: holding -# address: ${Felicity_Inv_BatteryCurrent} # 0x1109 -# value_type: S_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 BatteryPower" -# register_type: holding -# address: ${Felicity_Inv_BatteryPower} # 0x110A -# value_type: S_WORD -# register_count: 7 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 AC Output Voltage" -# register_type: holding -# address: ${Felicity_Inv_ACOutputVoltage} # 0x1111 -# value_type: U_WORD -# register_count: 6 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 AC Input Voltage" -# register_type: holding -# address: ${Felicity_Inv_ACInputVoltage} # 0x1117 -# value_type: U_WORD -# register_count: 2 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 AC Input Frequency" -# register_type: holding -# address: ${Felicity_Inv_ACInputFrequency} # 0x1119 -# value_type: U_WORD -# register_count: 5 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 AC Output Active Power" -# register_type: holding -# address: ${Felicity_Inv_ACOutputActivePower} # 0x111E -# value_type: S_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 AC Output Apparent Power" -# register_type: holding -# address: ${Felicity_Inv_ACOutputApparentPower} # 0x111F -# value_type: U_WORD -# register_count: 1 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 Load Percentage" -# register_type: holding -# address: ${Felicity_Inv_LoadPercentage} # 0x1120 -# value_type: U_WORD -# register_count: 6 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 PV Input Voltage" -# register_type: holding -# address: ${Felicity_Inv_PVInputVoltage} # 0x1126 -# value_type: U_WORD -# register_count: 4 -# -#- platform: modbus_controller -# modbus_controller_id: modbus_device2 -# name: "Inverter2 PV Input Power" -# register_type: holding -# address: ${Felicity_Inv_PVInputPower} # 0x112A -# value_type: S_WORD -# register_count: 1 - - - \ No newline at end of file + # human readable uptime sensor output to the text sensor above + - platform: uptime + name: Uptime in Days + id: uptime_sensor_days + update_interval: 10s + on_raw_value: + then: + - text_sensor.template.publish: + id: uptime_human + state: !lambda |- + int seconds = round(id(uptime_sensor_days).raw_state); + int days = seconds / (24 * 3600); + seconds = seconds % (24 * 3600); + int hours = seconds / 3600; + seconds = seconds % 3600; + int minutes = seconds / 60; + seconds = seconds % 60; + auto days_str = std::to_string(days); + auto hours_str = std::to_string(hours); + auto minutes_str = std::to_string(minutes); + auto seconds_str = std::to_string(seconds); + return ( + (days ? days_str + "d " : "") + + (hours ? hours_str + "h " : "") + + (minutes ? minutes_str + "m " : "") + + (seconds_str + "s") + ).c_str(); \ No newline at end of file