external_components: - source: type: local path: components # Path relative to this YAML file components: [ rtq6056 ] #ads1115_int, tlc59208f_ext, ds3231, ac_voltage_sensor ] #, ads131m08 ] packages: - !include ./common/wifi.yaml - !include common/canbus.yaml - !include common/modbus.yaml substitutions: name: sthome-ut3 friendly_name: "sthome-ut3" esphome: name: "${name}" friendly_name: "${friendly_name}" 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: ctr type: int restore_value: no initial_value: '0' - id: geyser_relay_status type: bool restore_value: yes initial_value: 'false' - id: can_msgctr type: int restore_value: no - id: can2_msgctr type: int restore_value: no - id: last_battery_message_time type: time_t restore_value: no - id: g_cb_cache # the cache is used to only accept a frame after it has been received a specified number of times within a specified period. this hopefully will iron out spurious corrupted frames type: solar::cbf_cache restore_value: no - id: g_cb_request_queue type: std::queue< std::set > restore_value: no debug: update_interval: 10s esp32: board: nodemcu-32s #esp32dev cpu_frequency: 240MHz framework: type: esp-idf #arduino # # Enable logging logger: level: DEBUG initial_level: INFO logs: uart_debug: INFO # If set to DEBUG, logs raw UART data in hex format, with direction indication (RX/TX) and timestamp. Can be very verbose, so use with caution. modbus: DEBUG modbus_controller: INFO light: INFO output: INFO canbus: DEBUG canbus_mcp2515: DEBUG sensor: INFO rtq6056: INFO # 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: #preferences: # flash_write_interval: 30s sun: id: sun_sensor latitude: !secret latitude longitude: !secret longitude time: - platform: homeassistant id: time_source interval: - interval: 30s then: - lambda: |- id(canbus_send_heartbeat).execute(); # - interval: 1.707s # then: # - uart.write: # data: "sthome3 heartbeat\r\n" # int loopsec = id(ctr) % 10; # id(ctr)++; # ESP_LOGI("main_loop", "Loop sec: %d", loopsec); # if (loopsec == 0) { # id(zone1_light).turn_on().set_brightness(1).perform(); # } else { # id(zone1_light).turn_off().perform(); # } # if (loopsec == 1) { # id(zone2_light).turn_on().set_brightness(1).perform(); # } else { # id(zone2_light).turn_off().perform(); # } # if (loopsec == 2) { # id(zone3_light).turn_on().set_brightness(1).perform(); # } else { # id(zone3_light).turn_off().perform(); # } # if (loopsec == 3) { # id(zone4_light).turn_on().set_brightness(1).perform(); # } else { # id(zone4_light).turn_off().perform(); # } # if (loopsec == 4) { # id(zone5_light).turn_on().set_brightness(1).perform(); # } else { # id(zone5_light).turn_off().perform(); # } # if (loopsec == 5) { # id(zone6_light).turn_on().set_brightness(1).perform(); # } else { # id(zone6_light).turn_off().perform(); # } # if (loopsec == 7) { # id(lights_frontyard_relay).turn_on(); # } else { # id(lights_frontyard_relay).turn_off(); # } # if (loopsec == 8) { # id(lights_backyard_relay).turn_on(); # } else { # id(lights_backyard_relay).turn_off(); # } # if (loopsec == 9) { # id(alarm_zone4_relay).turn_on(); # } else { # id(alarm_zone4_relay).turn_off(); # } i2c: - id: bus_a sda: GPIO21 scl: GPIO22 scan: true frequency: 200kHz spi: - id: spi_bus0 clk_pin: GPIO18 mosi_pin: GPIO23 miso_pin: GPIO19 interface: any uart: - id: sth_uart tx_pin: GPIO17 # Tx1 rx_pin: number: GPIO16 # Rx1 inverted: false mode: input: true pullup: true baud_rate: ${STHOME_ALARM_MODBUS_BAUD_RATE} stop_bits: 1 parity: NONE debug: direction: BOTH dummy_receiver: false after: delimiter: "\n" sequence: - lambda: UARTDebug::log_hex(direction, bytes, ','); ####################### MODBUS SERVER ############################################# modbus: - id: modbus_server uart_id: sth_uart send_wait_time: 1200ms #250ms disable_crc: false role: server modbus_controller: - id: modbus_alarm_server modbus_id: modbus_server address: ${STHOME_ALARM_MODBUS_DEVICE_ADDRESS} server_registers: - address: ${STHOME_ALARM_MODBUS_REG_ALARM_STATUS} value_type: S_DWORD_R read_lambda: |- uint16_t alarm_status = id(person_detected_switch).state ? 1 : 0; alarm_status |= id(alarm_zone4_relay).state ? 2 : 0; alarm_status |= id(lights_backyard_relay).state ? 4 : 0; alarm_status |= id(lights_frontyard_relay).state ? 8 : 0; alarm_status |= id(floodlight_test).state ? 16 : 0; alarm_status |= id(night_time).state ? 32 : 0; alarm_status |= id(zone1_triggered).state ? 64 : 0; alarm_status |= id(zone2_triggered).state ? 128 : 0; alarm_status |= id(zone3_triggered).state ? 256 : 0; alarm_status |= id(zone4_triggered).state ? 512 : 0; alarm_status |= id(zone5_triggered).state ? 1024 : 0; alarm_status |= id(zone6_triggered).state ? 2048 : 0; return alarm_status; - address: ${STHOME_ALARM_MODBUS_REG_ALARM_SIGNAL} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(alarm_signal).state; - address: ${STHOME_ALARM_MODBUS_REG_Z1Z4_CURRENT} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z1z4_current_ma).state; - address: ${STHOME_ALARM_MODBUS_REG_Z2Z5_CURRENT} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z2z5_current_ma).state; - address: ${STHOME_ALARM_MODBUS_REG_Z3Z6_CURRENT} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z3z6_current_ma).state; - address: ${STHOME_ALARM_MODBUS_REG_Z1Z4_BUS_VOLTAGE} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z1z4_bus_voltage).state; - address: ${STHOME_ALARM_MODBUS_REG_Z2Z5_BUS_VOLTAGE} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z2z5_bus_voltage).state; - address: ${STHOME_ALARM_MODBUS_REG_Z3Z6_BUS_VOLTAGE} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z3z6_bus_voltage).state; - address: ${STHOME_ALARM_MODBUS_REG_Z1Z4_POWER} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z1z4_power).state; - address: ${STHOME_ALARM_MODBUS_REG_Z2Z5_POWER} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z2z5_power).state; - address: ${STHOME_ALARM_MODBUS_REG_Z3Z6_POWER} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z3z6_power).state; - address: ${STHOME_ALARM_MODBUS_REG_Z1Z4_SHUNT_VOLTAGE} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z1z4_shunt_voltage).state; - address: ${STHOME_ALARM_MODBUS_REG_Z2Z5_SHUNT_VOLTAGE} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z2z5_shunt_voltage).state; - address: ${STHOME_ALARM_MODBUS_REG_Z3Z6_SHUNT_VOLTAGE} value_type: FP32_R read_lambda: |- return ${STHOME_ALARM_MODBUS_FLOAT_SCALE} * id(z3z6_shunt_voltage).state; ############################ MODBUS CLIENT EXAMPLE ############################################# #modbus: # - id: modbus_client # uart_id: sth_uart # send_wait_time: 250ms #1200ms #250ms # disable_crc: false # role: client # #modbus_controller: # - id: modbus_alarm_client # modbus_id: modbus_client # address: 0x01 # allow_duplicate_commands: False # command_throttle: 700ms #2022ms # update_interval: 10s #305s # offline_skip_updates: 2 # max_cmd_retries: 1 # setup_priority: -10 canbus: - platform: mcp2515 cs_pin: GPIO32 # CBCS spi_id: spi_bus0 id: canbus_sthome mode: NORMAL can_id: ${CB_CANBUS_ID03} bit_rate: 500KBPS on_frame: - can_id: 0 can_id_mask: 0 then: - lambda: |- id(can_msgctr)++; using namespace solar; auto time_obj = id(time_source).now(); //ESP_LOGI("CB REC", "%s", id(time_source).now().strftime("%a %d %b %Y - %I:%M:%S %p")); if(time_obj.is_valid()) { if (can_id >= 0x380 && can_id < 0x3C0) { auto cbitem = cbf_store_sthome(id(can_msgctr), can_id, x, remote_transmission_request, time_obj.timestamp); bool publish = id(g_cb_cache).additem(cbitem); if(publish) { ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str()); } } else { auto cbitem = cbf_store_sthome(id(can_msgctr), can_id, x, remote_transmission_request, time_obj.timestamp); ESP_LOGI(cbitem.tag().c_str(), "%s", cbitem.to_string().c_str()); } } output: - platform: ledc pin: number: GPIO14 inverted: false id: zone1_led frequency: 1000 Hz - platform: ledc pin: number: GPIO12 inverted: false id: zone2_led frequency: 1000 Hz - platform: ledc pin: number: GPIO13 inverted: false id: zone3_led frequency: 1000 Hz - platform: ledc pin: number: GPIO4 inverted: false id: zone4_led frequency: 1000 Hz - platform: ledc pin: number: GPIO2 inverted: false id: zone5_led frequency: 1000 Hz - platform: ledc pin: number: GPIO15 inverted: false id: zone6_led frequency: 1000 Hz light: - platform: monochromatic output: zone1_led name: "Zone 1" id: zone1_light default_transition_length: 5ms on_turn_on: - lambda: |- ESP_LOGV("zone", "Zone 1 on"); on_turn_off: - lambda: |- ESP_LOGV("zone", "Zone 1 off"); - platform: monochromatic output: zone2_led name: "Zone 2" id: zone2_light default_transition_length: 5ms on_turn_on: - lambda: |- ESP_LOGV("zone", "Zone 2 on"); on_turn_off: - lambda: |- ESP_LOGV("zone", "Zone 2 off"); - platform: monochromatic output: zone3_led name: "Zone 3" id: zone3_light default_transition_length: 5ms on_turn_on: - lambda: |- ESP_LOGV("zone", "Zone 3 on"); on_turn_off: - lambda: |- ESP_LOGV("zone", "Zone 3 off"); - platform: monochromatic output: zone4_led name: "Zone 4" id: zone4_light default_transition_length: 5ms on_turn_on: - lambda: |- ESP_LOGV("zone", "Zone 4 on"); on_turn_off: - lambda: |- ESP_LOGV("zone", "Zone 4 off"); - platform: monochromatic output: zone5_led name: "Zone 5" id: zone5_light default_transition_length: 5ms on_turn_on: - lambda: |- ESP_LOGV("zone", "Zone 5 on"); on_turn_off: - lambda: |- ESP_LOGV("zone", "Zone 5 off"); - platform: monochromatic output: zone6_led name: "Zone 6" id: zone6_light default_transition_length: 5ms on_turn_on: - lambda: |- ESP_LOGV("zone", "Zone 6 on"); on_turn_off: - lambda: |- ESP_LOGV("zone", "Zone 6 off"); 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" # if person detected, trigger zone4. If the alarm is armed, alarm_zone4_relay will cause the alarm to sound # if alarm is not armed, alarm_zone4_relay will not have any effect and the alarm will not sound. However, we will still turn on the floodlights for both backyard and frontyard if it's night time or floodlight test mode is on. # the person detected switch will be turned on by home-assistant automation when the person detection frigate sensor detects a person. We will use this switch to trigger the alarm and floodlights, and then turn it off after a short delay to reset the state for the next detection. - platform: template name: "Person Detected" id: person_detected_switch icon: "mdi:alarm-light-outline" restore_mode: RESTORE_DEFAULT_OFF turn_on_action: - switch.turn_on: alarm_zone4_relay - if: condition: or: - binary_sensor.is_on: night_time - binary_sensor.is_on: floodlight_test then: # if alarm is triggered and lights are enabled, turn on the floodlights for both backyard and frontyard - switch.turn_on: lights_backyard_relay - switch.turn_on: lights_frontyard_relay - platform: gpio pin: number: GPIO25 inverted: true id: alarm_zone4_relay name: "Alarm Zone 4" icon: "mdi:alarm-light-outline" restore_mode: RESTORE_DEFAULT_OFF on_turn_on: - delay: 20s - switch.turn_off: alarm_zone4_relay - platform: gpio pin: number: GPIO26 inverted: true id: lights_backyard_relay 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: lights_backyard_relay - platform: gpio pin: number: GPIO27 inverted: true id: lights_frontyard_relay name: "Floodlights Frontyard" icon: "mdi:light-flood-down" restore_mode: RESTORE_DEFAULT_OFF # the frontyard floodlight auto turns off in x 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: lights_frontyard_relay # define DIGITAL_D1 04 binary_sensor: ##### MODBUS CLIENT BINARY SENSORS ### # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_person_detected # name: "MBC Person Detected" # register_type: read # address: 0x0001 # bitmask: 0x1 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_alarm_zone4_relay # name: "MBC Alarm Zone 4 Relay" # register_type: read # address: 0x0001 # bitmask: 0x2 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_lights_backyard_relay # name: "MBC Lights Backyard Relay" # register_type: read # address: 0x0001 # bitmask: 0x4 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_lights_frontyard_relay # name: "MBC Lights Frontyard Relay" # register_type: read # address: 0x0001 # bitmask: 0x8 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_floodlight_test # name: "MBC Floodlight Test" # register_type: read # address: 0x0001 # bitmask: 0x10 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_night_time # name: "MBC Night Time" # register_type: read # address: 0x0001 # bitmask: 0x20 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_zone1_triggered # name: "MBC Zone 1 Triggered" # register_type: read # address: 0x0001 # bitmask: 0x40 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_zone2_triggered # name: "MBC Zone 2 Triggered" # register_type: read # address: 0x0001 # bitmask: 0x80 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_zone3_triggered # name: "MBC Zone 3 Triggered" # register_type: read # address: 0x0001 # bitmask: 0x100 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_zone4_triggered # name: "MBC Zone 4 Triggered" # register_type: read # address: 0x0001 # bitmask: 0x200 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_zone5_triggered # name: "MBC Zone 5 Triggered" # register_type: read # address: 0x0001 # bitmask: 0x400 # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_zone6_triggered # name: "MBC Zone 6 Triggered" # register_type: read # address: 0x0001 # bitmask: 0x800 ### END OF MODBUS CLIENT BINARY SENSORS ### - platform: gpio # device_class: light id: floodlight_test pin: number: GPIO33 mode: input: true pullup: true filters: - delayed_off: 100ms name: "Floodlights Test Mode" icon: "mdi:lightbulb-on-outline" - platform: template name: "Night Time" id: night_time lambda: |- // we will use the sun elevation to determine if the floodlights should be on or not. If the sun elevation is below -6 degrees, we will consider it as night time return false; // debug double sun_elevation = id(sun_sensor).elevation(); return (sun_elevation <= -6); // -6° = civil twilight, -12° = nautical twilight, -18° = astronomical twilight - platform: template name: "Zone 1 Triggered" id: zone1_triggered lambda: |- // NB! LED will light up when zone is interrupted, so the logic is inverted. When the zone is not interrupted, there will be current flowing through the shunt and the LED will be off. When the zone is interrupted, there will be no current flowing through the shunt and the LED will be on. So we will use the current reading to determine if the zone is interrupted or not. We will also use the current reading to determine if both zones S1 and S4 are active or not, since they are on the same shunt and we can only get combined current for both zones. // Using up to maximum of 13V supply, 2200ohm and 3300ohm resistors, we can get a maximum of around 10.91mA current through the shunt when both zones S1 and S4 are active, below 7.6mA and above 4.6mA when S1 is active and S4 is not active, and below 3.3mA when S1 is not active and S4 is active. So we can use 3.3mA as a threshold to determine if S1 is #active r not, and 7.6mA as a threshold to determine if S4 is active or not. If the current is below 3.3mA, we can assume that both zones are inactive and return false. If the #current is bove 7.6mA, we can assume that both zones are active and return true. If the current is between 3.3mA and 7.6mA, we can assume that only one of the zones is active #and return true or zone 1 and false for zone 4. double current = id(z1z4_current_ma).state; // in mA if (current >= 8) { id(zone1_light).turn_on().set_brightness(1).perform(); return true; // Error condition, current is higher than expected. This could be a full short circuit done by burglar to bypass the shunt and make the alarm think that zone 1 is not active, so we will treat it as zone 1 being active to be safe. We can later add a separate binary sensor for short circuit detection if needed. } if (current > 4.5) { id(zone1_light).turn_off().perform(); return false; // Zone 1 or both zones are inactive } id(zone1_light).turn_on().set_brightness(1).perform(); return true; // Zone 1 is active (either alone or with Zone 4) - platform: template name: "Zone 4 Triggered" id: zone4_triggered lambda: |- double current = id(z1z4_current_ma).state; // in mA if(current < 2) { id(zone4_light).turn_on().set_brightness(1).perform(); return true; // both zones are active } if (current < 4.5) { id(zone4_light).turn_off().perform(); return false; // Zone 4 is inactive, Zone 1 is active } if (current < 6) { id(zone4_light).turn_on().set_brightness(1).perform(); return true; // Zone 4 is active, Zone 1 is inactive } if (current < 8){ id(zone4_light).turn_off().perform(); return false; // Zone 4 is inactive, Zone 1 is inactive } id(zone4_light).turn_on().set_brightness(1).perform(); return true; // Error case, current is higher than expected. This could be a full short circuit done by burglar to bypass the shunt and make the alarm think that zone 4 is not active, so we will treat it as zone 4 being active to be safe. We can later add a separate binary sensor for short circuit detection if needed. - platform: template name: "Zone 2 Triggered" id: zone2_triggered lambda: |- double current = id(z2z5_current_ma).state; // in mA if (current >= 8) { id(zone2_light).turn_on().set_brightness(1).perform(); return true; } if (current > 4.5) { id(zone2_light).turn_off().perform(); return false; // Zone 2 or both zones are inactive } id(zone2_light).turn_on().set_brightness(1).perform(); return true; // Zone 2 is active (either alone or with Zone 5) - platform: template name: "Zone 5 Triggered" id: zone5_triggered lambda: |- double current = id(z2z5_current_ma).state; // in mA if(current < 2) { id(zone5_light).turn_on().set_brightness(1).perform(); return true; // both zones are active } if (current < 4.5) { id(zone5_light).turn_off().perform(); return false; // Zone 5 is inactive, Zone 2 is active } if (current < 6) { id(zone5_light).turn_on().set_brightness(1).perform(); return true; // Zone 5 is active, Zone 2 is inactive } if (current < 8){ id(zone5_light).turn_off().perform(); return false; // Zone 5 is inactive, Zone 2 is inactive } id(zone5_light).turn_on().set_brightness(1).perform(); return true; // Error case - platform: template name: "Zone 3 Triggered" id: zone3_triggered lambda: |- double current = id(z3z6_current_ma).state; // in mA if (current >= 8) { id(zone3_light).turn_on().set_brightness(1).perform(); return true; } if (current > 4.5) { id(zone3_light).turn_off().perform(); return false; // Zone 3 or both zones are inactive } id(zone3_light).turn_on().set_brightness(1).perform(); return true; // Zone 3 is active (either alone or with Zone 6) - platform: template name: "Zone 6 Triggered" id: zone6_triggered lambda: |- double current = id(z3z6_current_ma).state; // in mA if(current < 2) { id(zone6_light).turn_on().set_brightness(1).perform(); return true; // both zones are active } if (current < 4.5) { id(zone6_light).turn_off().perform(); return false; // Zone 6 is inactive, Zone 3 is active } if (current < 6) { id(zone6_light).turn_on().set_brightness(1).perform(); return true; // Zone 6 is active, Zone 3 is inactive } if (current < 8){ id(zone6_light).turn_off().perform(); return false; // Zone 6 is inactive, Zone 3 is inactive } id(zone6_light).turn_on().set_brightness(1).perform(); return true; // Error case sensor: #### MODBUS CLIENT SENSORS ### # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z1z4_current # name: "MBC Z1Z4 Current" # address: 0x0002 # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "mA" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z2z5_current # name: "MBC Z2Z5 Current" # address: 0x0006 # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "mA" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z3z6_current # name: "MBC Z3Z6 Current" # address: 0x000A # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "mA" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z1z4_bus_voltage # name: "MBC Z1Z4 Bus Voltage" # address: 0x000E # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "V" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z2z5_bus_voltage # name: "MBC Z2Z5 Bus Voltage" # address: 0x0012 # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "V" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z3z6_bus_voltage # name: "MBC Z3Z6 Bus Voltage" # address: 0x0016 # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "V" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z1z4_power # name: "MBC Z1Z4 Power" # address: 0x001A # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "W" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z2z5_power # name: "MBC Z2Z5 Power" # address: 0x001E # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "W" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z3z6_power # name: "MBC Z3Z6 Power" # address: 0x0022 # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "W" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z1z4_shunt_voltage # name: "MBC Z1Z4 Shunt Voltage" # address: 0x0026 # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "V" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z2z5_shunt_voltage # name: "MBC Z2Z5 Shunt Voltage" # address: 0x002A # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "V" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_z3z6_shunt_voltage # name: "MBC Z3Z6 Shunt Voltage" # address: 0x002E # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "V" # lambda: |- # return x / 1024.0; # # - platform: modbus_controller # modbus_controller_id: modbus_alarm_client # id: mbc_alarm_signal # name: "MBC Alarm Signal" # address: 0x0032 # register_type: holding # value_type: S_WORD # register_count: 4 # unit_of_measurement: "V" # lambda: |- # return x / 1024.0; ### END OF MODBUS CLIENT SENSORS ### - platform: rtq6056 address: 0x40 id: adc_z1z4 # Zone S1 and S4 are on the same shunt, so we can only get combined current for both zones. We will use this sensor for both zones and then split the readings in the template binary_sensor shunt_resistance: 5 ohm max_current: 16mA # adc time used for both, Bus Voltage and Shunt Voltage adc_time: 140us adc_averaging: 16 update_interval: 1s current: id: z1z4_current power: name: "Z1_Z4 Power" id: z1z4_power bus_voltage: name: "Z1_Z4 Bus Voltage" id: z1z4_bus_voltage shunt_voltage: name: "Z1_Z4 Shunt Voltage" id: z1z4_shunt_voltage - platform: template name: "Z1_Z4 Current" id: z1z4_current_ma unit_of_measurement: "mA" accuracy_decimals: 3 lambda: |- return 1000 * id(z1z4_current).state; - platform: rtq6056 address: 0x41 id: adc_z2z5 # Zone S2 and S5 are on the same shunt, so we can only get combined current for both zones. We will use this sensor for both zones and then split the readings in the template binary_sensor shunt_resistance: 5.5 ohm max_current: 16mA # adc time used for both, Bus Voltage and Shunt Voltage adc_time: 140us adc_averaging: 16 update_interval: 1s current: id: z2z5_current power: name: "Z2_Z5 Power" id: z2z5_power bus_voltage: name: "Z2_Z5 Bus Voltage" id: z2z5_bus_voltage shunt_voltage: name: "Z2_Z5 Shunt Voltage" id: z2z5_shunt_voltage - platform: template name: "Z2_Z5 Current" id: z2z5_current_ma unit_of_measurement: "mA" accuracy_decimals: 3 lambda: |- return 1000 * id(z2z5_current).state; - platform: rtq6056 address: 0x42 id: adc_z3z6 # Zone S3 and S6 are on the same shunt, so we can only get combined current for both zones. We will use this sensor for both zones and then split the readings in the template binary_sensor shunt_resistance: 5 ohm max_current: 16mA # adc time used for both, Bus Voltage and Shunt Voltage adc_time: 140us adc_averaging: 16 update_interval: 1s current: id: z3z6_current power: name: "Z3_Z6 Power" id: z3z6_power bus_voltage: name: "Z3_Z6 Bus Voltage" id: z3z6_bus_voltage shunt_voltage: name: "Z3_Z6 Shunt Voltage" id: z3z6_shunt_voltage - platform: template name: "Z3_Z6 Current" id: z3z6_current_ma unit_of_measurement: "mA" accuracy_decimals: 3 lambda: |- return 1000 * id(z3z6_current).state; - platform: adc pin: 39 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: # alarm is sounding when the signal is above 1.5V, so we can use this threshold to determine if the alarm is triggered or not. If the alarm is triggered by external trigger, we will turn on the floodlights for both backyard and frontyard, whether it is night time or not. The floodlights will be turned on for 4min 14 sec, which is the auto turn off time of the floodlights, so we don't need to worry about turning them off manually. lambda: |- if (id(alarm_signal).state > 1.5) { id(lights_frontyard_relay).turn_on(); id(lights_backyard_relay).turn_on(); } # 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(); script: - id: canbus_send_heartbeat then: lambda: |- using namespace solar; std::vector x(cbf_sthome::heartbeat.begin(), cbf_sthome::heartbeat.end()); id(g_cb_cache).send_frame(id(canbus_sthome), cbf_sthome::CB_CANBUS_ID03, x);