2598 lines
83 KiB
YAML
2598 lines
83 KiB
YAML
packages:
|
|
- !include common/wifi.yaml
|
|
- !include common/canbus.yaml
|
|
- !include common/felicityinverter.yaml
|
|
|
|
substitutions:
|
|
name: sthome-ut9
|
|
friendly_name: "sthome-ut9"
|
|
# #ALLOWED_CHARACTERS_FULL: " !#%\"'()+,-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWYZ[]_abcdefghijklmnopqrstuvwxyz{|}°²³µ¿ÁÂÄÅÉÖÚßàáâãäåæçèéêëìíîðñòóôõöøùúûüýþāăąćčďĐđēėęěğĮįıļľŁłńňőřśšťũūůűųźŻżŽžơưșțΆΈΌΐΑΒΓΔΕΖΗΘΚΜΝΠΡΣΤΥΦάέήίαβγδεζηθικλμνξοπρςστυφχψωϊόύώАБВГДЕЖЗИКЛМНОПРСТУХЦЧШЪЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяёђєіїјљњћ"
|
|
# ALLOWED_CHARACTERS: " !#%\"'()+,-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWYZ[]_abcdefghijklmnopqrstuvwxyz{|}°²³µ•"
|
|
# DD_MAX_YEARS: "5"
|
|
#
|
|
globals:
|
|
- id: g_inv1_power_flow
|
|
type: uint16_t
|
|
restore_value: no
|
|
initial_value: '0'
|
|
- id: g_inv2_power_flow
|
|
type: uint16_t
|
|
restore_value: no
|
|
initial_value: '0'
|
|
# - id: g_month_idx
|
|
# type: int
|
|
# restore_value: yes
|
|
# initial_value: '0'
|
|
# - id: g_year_idx
|
|
# type: int
|
|
# restore_value: yes
|
|
# initial_value: '0'
|
|
# - id: g_options_year
|
|
# type: char[1 + ${DD_MAX_YEARS} * 5]
|
|
# restore_value: yes
|
|
## initial_value: "{2022\n2023\n2024\n2025\n2026}"
|
|
# - id: g_geyser_heating_on
|
|
# type: bool
|
|
# restore_value: no
|
|
# initial_value: '0'
|
|
# - id: g_utility_on
|
|
# type: bool
|
|
# restore_value: no
|
|
# initial_value: '0'
|
|
# - id: g_geyser_top_temperature
|
|
# type: double
|
|
# restore_value: yes
|
|
# initial_value: '0'
|
|
# - id: g_geyser_bottom_temperature
|
|
# type: double
|
|
# restore_value: yes
|
|
# initial_value: '0'
|
|
# - id: can_lastid
|
|
# type: uint32_t
|
|
# restore_value: no
|
|
# - id: can_lastframe
|
|
# type: std::vector<uint8_t>
|
|
# restore_value: no
|
|
|
|
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]
|
|
|
|
esp32:
|
|
# board: nodemcu-32s
|
|
board: esp32dev
|
|
framework:
|
|
type: arduino
|
|
#type: esp-idf
|
|
|
|
#debug:
|
|
# update_interval: 5s
|
|
|
|
# Enable logging
|
|
logger:
|
|
level: DEBUG
|
|
logs:
|
|
canbus: INFO
|
|
|
|
# Enable Home Assistant API
|
|
api:
|
|
encryption:
|
|
key: "LI7j37zs9HsWNsUZ5c83leThmhHsgIVReAPoc9U6pVU="
|
|
|
|
ota:
|
|
- platform: esphome
|
|
password: "8ebd5bcefbdc833a5f6ddc4e8ba56e39"
|
|
|
|
wifi:
|
|
power_save_mode: none # stops display flickering
|
|
manual_ip:
|
|
static_ip: 10.0.2.9
|
|
# Enable fallback hotspot (captive portal) in case wifi connection fails
|
|
ap:
|
|
ssid: "${name} Fallback Hotspot"
|
|
password: "iZxjpw7ucRs4"
|
|
|
|
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
|
|
send_wait_time: 1200ms #250ms
|
|
disable_crc: false
|
|
role: client
|
|
|
|
- id: modbus2
|
|
uart_id: inv_uart2
|
|
send_wait_time: 1200ms #250ms
|
|
disable_crc: false
|
|
role: client
|
|
|
|
modbus_controller:
|
|
- id: modbus_device1
|
|
modbus_id: modbus1
|
|
address: 0x01
|
|
allow_duplicate_commands: False
|
|
command_throttle: 700ms #2022ms
|
|
update_interval: 60s #305s
|
|
offline_skip_updates: 2
|
|
max_cmd_retries: 1
|
|
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
|
|
|
|
text_sensor:
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 SerialNo"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_SerialNo} # 0xF804
|
|
response_size: 14 # should be 10, but absorbing extra four bytes
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
char buffer[32];
|
|
uint16_t sn0 = modbus_controller::word_from_hex_str(x, 0);
|
|
uint16_t sn1 = modbus_controller::word_from_hex_str(x, 2);
|
|
uint16_t sn2 = modbus_controller::word_from_hex_str(x, 4);
|
|
uint16_t sn3 = modbus_controller::word_from_hex_str(x, 6);
|
|
uint16_t sn4 = modbus_controller::word_from_hex_str(x, 8);
|
|
snprintf(buffer, sizeof(buffer), "%04d%04d%04d%04d%04d", sn0, sn1, sn2, sn3, sn4);
|
|
return std::string(buffer).substr(0, 14);
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 Type"
|
|
id: inverter1_type
|
|
bitmask: 0
|
|
register_type: holding
|
|
address: ${Felicity_Inv_Type} # 0xF800
|
|
response_size: 2
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
switch (value) {
|
|
case 0x50: return std::string("High Frequency Inverter");
|
|
default: return std::string("Unknown");
|
|
}
|
|
return x;
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 Sub Type"
|
|
id: inverter1_subtype
|
|
bitmask: 0
|
|
register_type: holding
|
|
address: ${Felicity_Inv_SubType} # 0xF801
|
|
response_size: 6 # should be 2, but absorbing extra four bytes
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
switch (value) {
|
|
case 0x0204: return std::string("3024 (3000VA/24V)");
|
|
case 0x0408: return std::string("5048 (5000VA/48V)");
|
|
default: return std::string("Unknown");
|
|
}
|
|
return x;
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 CPU1 F/W Version"
|
|
bitmask: 0
|
|
register_type: holding
|
|
address: ${Felicity_Inv_CPU1_FW_Version} # 0xF80B
|
|
response_size: 2
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
return std::to_string(value);
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 CPU2 F/W Version"
|
|
bitmask: 0
|
|
register_type: holding
|
|
address: ${Felicity_Inv_CPU2_FW_Version} # 0xF80C
|
|
response_size: 2
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
return std::to_string(value);
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 Working Mode"
|
|
address: ${Felicity_Inv_WorkingMode} # 0x1101
|
|
bitmask: 0
|
|
register_type: holding
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
switch(value) {
|
|
case 0: return std::string("Power On");
|
|
case 1: return std::string("Standby");
|
|
case 2: return std::string("Bypass");
|
|
case 3: return std::string("Battery");
|
|
case 4: return std::string("Fault");
|
|
case 5: return std::string("Line");
|
|
case 6: return std::string("PV Charge");
|
|
}
|
|
return std::string("Unknown");
|
|
register_count: 1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 Charge Mode"
|
|
address: ${Felicity_Inv_BatteryChargingStage} # 0x1102
|
|
bitmask: 0
|
|
register_type: holding
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
switch(value) {
|
|
case 0: return std::string("Idle");
|
|
case 1: return std::string("Bulk");
|
|
case 2: return std::string("Absorption");
|
|
case 3: return std::string("Float");
|
|
}
|
|
return std::string("Unknown");
|
|
register_count: 1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 SerialNo"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_SerialNo} # 0xF804
|
|
response_size: 14 # should be 10, but absorbing extra four bytes
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
char buffer[32];
|
|
uint16_t sn0 = modbus_controller::word_from_hex_str(x, 0);
|
|
uint16_t sn1 = modbus_controller::word_from_hex_str(x, 2);
|
|
uint16_t sn2 = modbus_controller::word_from_hex_str(x, 4);
|
|
uint16_t sn3 = modbus_controller::word_from_hex_str(x, 6);
|
|
uint16_t sn4 = modbus_controller::word_from_hex_str(x, 8);
|
|
snprintf(buffer, sizeof(buffer), "%04d%04d%04d%04d%04d", sn0, sn1, sn2, sn3, sn4);
|
|
return std::string(buffer).substr(0, 14);
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 Type"
|
|
id: inverter2_type
|
|
bitmask: 0
|
|
register_type: holding
|
|
address: ${Felicity_Inv_Type} # 0xF800
|
|
response_size: 2
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
switch (value) {
|
|
case 0x50: return std::string("High Frequency Inverter");
|
|
default: return std::string("Unknown");
|
|
}
|
|
return x;
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 Sub Type"
|
|
id: inverter2_subtype
|
|
bitmask: 0
|
|
register_type: holding
|
|
address: ${Felicity_Inv_SubType} # 0xF801
|
|
response_size: 6 # should be 2, but absorbing extra four bytes
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
switch (value) {
|
|
case 0x0204: return std::string("3024 (3000VA/24V)");
|
|
case 0x0408: return std::string("5048 (5000VA/48V)");
|
|
default: return std::string("Unknown");
|
|
}
|
|
return x;
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 CPU1 F/W Version"
|
|
bitmask: 0
|
|
register_type: holding
|
|
address: ${Felicity_Inv_CPU1_FW_Version} # 0xF80B
|
|
response_size: 2
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
return std::to_string(value);
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 CPU2 F/W Version"
|
|
bitmask: 0
|
|
register_type: holding
|
|
address: ${Felicity_Inv_CPU2_FW_Version} # 0xF80C
|
|
response_size: 2
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
return std::to_string(value);
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 Working Mode"
|
|
address: ${Felicity_Inv_WorkingMode} # 0x1101
|
|
bitmask: 0
|
|
register_type: holding
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
switch(value) {
|
|
case 0: return std::string("Power On");
|
|
case 1: return std::string("Standby");
|
|
case 2: return std::string("Bypass");
|
|
case 3: return std::string("Battery");
|
|
case 4: return std::string("Fault");
|
|
case 5: return std::string("Line");
|
|
case 6: return std::string("PV Charge");
|
|
}
|
|
return std::string("Unknown");
|
|
register_count: 1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 Charge Mode"
|
|
address: ${Felicity_Inv_BatteryChargingStage} # 0x1102
|
|
bitmask: 0
|
|
register_type: holding
|
|
raw_encode: HEXBYTES
|
|
lambda: |-
|
|
uint16_t value = modbus_controller::word_from_hex_str(x, 0);
|
|
switch(value) {
|
|
case 0: return std::string("Idle");
|
|
case 1: return std::string("Bulk");
|
|
case 2: return std::string("Absorption");
|
|
case 3: return std::string("Float");
|
|
}
|
|
return std::string("Unknown");
|
|
register_count: 1
|
|
|
|
sensor:
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 SettingDataSn"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_SettingDataSn} # 0x1100
|
|
accuracy_decimals: 0
|
|
value_type: U_WORD
|
|
register_count: 1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 Fault Code"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_FaultCode} # 0x1103
|
|
value_type: U_WORD
|
|
register_count: 1
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
id: inv1_power_flow_msg
|
|
register_type: holding
|
|
address: ${Felicity_Inv_PowerFlowMsg} # 0x1104
|
|
value_type: U_WORD
|
|
register_count: 4
|
|
lambda: |-
|
|
id(g_inv1_power_flow) = x;
|
|
return x;
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 Battery Voltage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_BatteryVoltage} # 0x1108
|
|
value_type: U_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "V"
|
|
device_class: voltage
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.01
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 Battery Current"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_BatteryCurrent} # 0x1109
|
|
value_type: S_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "A"
|
|
device_class: current
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 BatteryPower"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_BatteryPower} # 0x110A
|
|
value_type: S_WORD
|
|
register_count: 7
|
|
unit_of_measurement: "W"
|
|
device_class: power
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 AC Output Voltage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACOutputVoltage} # 0x1111
|
|
value_type: U_WORD
|
|
register_count: 6
|
|
unit_of_measurement: "V"
|
|
device_class: voltage
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 AC Input Voltage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACInputVoltage} # 0x1117
|
|
value_type: U_WORD
|
|
register_count: 2
|
|
unit_of_measurement: "V"
|
|
device_class: voltage
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 AC Input Frequency"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACInputFrequency} # 0x1119
|
|
value_type: U_WORD
|
|
register_count: 5
|
|
unit_of_measurement: "Hz"
|
|
device_class: frequency
|
|
accuracy_decimals: 2
|
|
filters:
|
|
- multiply: 0.01
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 AC Output Active Power"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACOutputActivePower} # 0x111E
|
|
value_type: S_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "W"
|
|
device_class: power
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 AC Output Apparent Power"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACOutputApparentPower} # 0x111F
|
|
value_type: U_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "VA"
|
|
device_class: apparent_power
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 Load Percentage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_LoadPercentage} # 0x1120
|
|
value_type: U_WORD
|
|
register_count: 6
|
|
unit_of_measurement: "%"
|
|
device_class: power
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 PV Input Voltage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_PVInputVoltage} # 0x1126
|
|
value_type: U_WORD
|
|
register_count: 4
|
|
unit_of_measurement: "V"
|
|
device_class: voltage
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device1
|
|
name: "Inv1 PV Input Power"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_PVInputPower} # 0x112A
|
|
value_type: S_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "W"
|
|
device_class: power
|
|
accuracy_decimals: 0
|
|
|
|
############### modbus device 2 ###############
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 SettingDataSn"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_SettingDataSn} # 0x1100
|
|
accuracy_decimals: 0
|
|
value_type: U_WORD
|
|
register_count: 1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 Fault Code"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_FaultCode} # 0x1103
|
|
value_type: U_WORD
|
|
register_count: 1
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
id: inv2_power_flow_msg
|
|
register_type: holding
|
|
address: ${Felicity_Inv_PowerFlowMsg} # 0x1104
|
|
value_type: U_WORD
|
|
register_count: 4
|
|
lambda: |-
|
|
id(g_inv2_power_flow) = x;
|
|
return x;
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 Battery Voltage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_BatteryVoltage} # 0x1108
|
|
value_type: U_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "V"
|
|
device_class: voltage
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.01
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 Battery Current"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_BatteryCurrent} # 0x1109
|
|
value_type: S_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "A"
|
|
device_class: current
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 BatteryPower"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_BatteryPower} # 0x110A
|
|
value_type: S_WORD
|
|
register_count: 7
|
|
unit_of_measurement: "W"
|
|
device_class: power
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 AC Output Voltage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACOutputVoltage} # 0x1111
|
|
value_type: U_WORD
|
|
register_count: 6
|
|
unit_of_measurement: "V"
|
|
device_class: voltage
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 AC Input Voltage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACInputVoltage} # 0x1117
|
|
value_type: U_WORD
|
|
register_count: 2
|
|
unit_of_measurement: "V"
|
|
device_class: voltage
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 AC Input Frequency"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACInputFrequency} # 0x1119
|
|
value_type: U_WORD
|
|
register_count: 5
|
|
unit_of_measurement: "Hz"
|
|
device_class: frequency
|
|
accuracy_decimals: 2
|
|
filters:
|
|
- multiply: 0.01
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 AC Output Active Power"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACOutputActivePower} # 0x111E
|
|
value_type: S_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "W"
|
|
device_class: power
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 AC Output Apparent Power"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_ACOutputApparentPower} # 0x111F
|
|
value_type: U_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "VA"
|
|
device_class: apparent_power
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 Load Percentage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_LoadPercentage} # 0x1120
|
|
value_type: U_WORD
|
|
register_count: 6
|
|
unit_of_measurement: "%"
|
|
device_class: power
|
|
accuracy_decimals: 0
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 PV Input Voltage"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_PVInputVoltage} # 0x1126
|
|
value_type: U_WORD
|
|
register_count: 4
|
|
unit_of_measurement: "V"
|
|
device_class: voltage
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- multiply: 0.1
|
|
|
|
- platform: modbus_controller
|
|
modbus_controller_id: modbus_device2
|
|
name: "Inv2 PV Input Power"
|
|
register_type: holding
|
|
address: ${Felicity_Inv_PVInputPower} # 0x112A
|
|
value_type: S_WORD
|
|
register_count: 1
|
|
unit_of_measurement: "W"
|
|
device_class: power
|
|
accuracy_decimals: 0
|
|
|
|
binary_sensor:
|
|
- platform: template
|
|
name: "Inv1 Battery Connected"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv1_power_flow) & 0x8000;
|
|
|
|
- platform: template
|
|
name: "Inv1 Line Normal"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv1_power_flow) & 0x4000;
|
|
|
|
- platform: template
|
|
name: "Inv1 PV Input Normal"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv1_power_flow) & 0x2000;
|
|
|
|
- platform: template
|
|
name: "Inv1 Load Connect Allowed"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv1_power_flow) & 0x1000;
|
|
|
|
- platform: template
|
|
name: "Inv1 PV MPPT Working"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv1_power_flow) & 0x0080;
|
|
|
|
- platform: template
|
|
name: "Inv1 Load Connected"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv1_power_flow) & 0x0040;
|
|
|
|
- platform: template
|
|
name: "Inv1 Power Flow Version Supported"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv1_power_flow) & 0x0001;
|
|
|
|
- platform: template
|
|
name: "Inv1 Battery Charging"
|
|
device_class: battery_charging
|
|
lambda: |-
|
|
int battery_flow = (id(g_inv1_power_flow) >> 10) & 3;
|
|
return battery_flow & 0x01;
|
|
|
|
- platform: template
|
|
name: "Inv1 Battery Discharging"
|
|
# device_class: battery_charging
|
|
lambda: |-
|
|
int battery_flow = (id(g_inv1_power_flow) >> 10) & 3;
|
|
return battery_flow & 0x02;
|
|
|
|
- platform: template
|
|
name: "Inv1 Draw Power from Line"
|
|
lambda: |-
|
|
int line_flow = (id(g_inv1_power_flow) >> 8) & 3;
|
|
return line_flow & 0x01;
|
|
|
|
- platform: template
|
|
name: "Inv1 Feed Power to Line"
|
|
lambda: |-
|
|
int line_flow = (id(g_inv1_power_flow) >> 8) & 3;
|
|
return line_flow & 0x10;
|
|
|
|
- platform: template
|
|
name: "Inv2 Battery Connected"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv2_power_flow) & 0x8000;
|
|
|
|
- platform: template
|
|
name: "Inv2 Line Normal"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv2_power_flow) & 0x4000;
|
|
|
|
- platform: template
|
|
name: "Inv2 PV Input Normal"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv2_power_flow) & 0x2000;
|
|
|
|
- platform: template
|
|
name: "Inv2 Load Connect Allowed"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv2_power_flow) & 0x1000;
|
|
|
|
- platform: template
|
|
name: "Inv2 PV MPPT Working"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv2_power_flow) & 0x0080;
|
|
|
|
- platform: template
|
|
name: "Inv2 Load Connected"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv2_power_flow) & 0x0040;
|
|
|
|
- platform: template
|
|
name: "Inv2 Power Flow Version Supported"
|
|
# device_class: problem
|
|
lambda: |-
|
|
return id(g_inv2_power_flow) & 0x0001;
|
|
|
|
- platform: template
|
|
name: "Inv2 Battery Charging"
|
|
device_class: battery_charging
|
|
lambda: |-
|
|
int battery_flow = (id(g_inv2_power_flow) >> 10) & 3;
|
|
return battery_flow & 0x01;
|
|
|
|
- platform: template
|
|
name: "Inv2 Battery Discharging"
|
|
# device_class: battery_charging
|
|
lambda: |-
|
|
int battery_flow = (id(g_inv2_power_flow) >> 10) & 3;
|
|
return battery_flow & 0x02;
|
|
|
|
- platform: template
|
|
name: "Inv2 Draw Power from Line"
|
|
lambda: |-
|
|
int line_flow = (id(g_inv2_power_flow) >> 8) & 3;
|
|
return line_flow & 0x01;
|
|
|
|
- platform: template
|
|
name: "Inv2 Feed Power to Line"
|
|
lambda: |-
|
|
int line_flow = (id(g_inv2_power_flow) >> 8) & 3;
|
|
return line_flow & 0x10;
|
|
################################################################################################3
|
|
#### OLD STHOME-9 CONFIG STARTS HERE
|
|
#time:
|
|
# - platform: homeassistant
|
|
# id: time_source
|
|
# update_interval: 360min # Change sync interval from default 5min to 6 hours
|
|
# on_time_sync:
|
|
# then:
|
|
## - if: # Publish the time the device was last restarted, but only once.
|
|
## condition:
|
|
## lambda: 'return id(device_last_restart).state == "";'
|
|
## then:
|
|
## - text_sensor.template.publish:
|
|
## id: device_last_restart
|
|
## state: !lambda 'return id(time_source).now().strftime("%a %d %b %Y - %I:%M:%S %p");'
|
|
## - script.execute: ind_heating_update
|
|
## - script.execute: time_update
|
|
## - script.execute: init_calendar
|
|
#
|
|
# on_time:
|
|
# - minutes: '*'
|
|
# seconds: '*'
|
|
# then:
|
|
## - script.execute: ind_heating_update
|
|
## - script.execute: time_update
|
|
## - lambda: |-
|
|
## id(get_calendar_days_state).execute("T");
|
|
# #- script.execute: get_calendar_days_state
|
|
##
|
|
## - hours: 1,2,3,4
|
|
## minutes: 5
|
|
## seconds: 0
|
|
## then:
|
|
## - switch.turn_on: switch_antiburn
|
|
## - hours: 1,2,3,4
|
|
## minutes: 35
|
|
## seconds: 0
|
|
## then:
|
|
## - switch.turn_off: switch_antiburn
|
|
#
|
|
#font:
|
|
# - file: "gfonts://Roboto"
|
|
# id: roboto_200
|
|
# size: 200
|
|
# bpp: 4
|
|
# glyphs: [
|
|
# 0123456789,.,°,a,n,
|
|
# "\u0020", # space
|
|
# "\u003A", # colon
|
|
# ]
|
|
# - file: "gfonts://Roboto"
|
|
# id: roboto_192
|
|
# size: 192
|
|
# bpp: 4
|
|
# glyphs: [
|
|
# 0123456789,.,°,a,n,
|
|
# "\u0020", # space
|
|
# "\u003A", # colon
|
|
# ]
|
|
# - file: "gfonts://Roboto"
|
|
# id: geyser_temperature_font2
|
|
# size: 60
|
|
# bpp: 4
|
|
# glyphs: [
|
|
# °,C,
|
|
# ]
|
|
# - file: "gfonts://Roboto"
|
|
# id: geyser_temperature_font3
|
|
# size: 30
|
|
# bpp: 4
|
|
# glyphs: [
|
|
# b,o,m,p,t,
|
|
# ]
|
|
# - file: "fonts/misc/materialdesignicons-webfont.ttf"
|
|
# id: font_icon_small
|
|
# size: 24 #45
|
|
# glyphs: [
|
|
# "\U0000F5A9",
|
|
# ]
|
|
#
|
|
#color:
|
|
# - id: grey_light
|
|
# hex: 'e0e0e0'
|
|
#
|
|
##image:
|
|
### - file: https://esphome.io/_static/favicon-512x512.png
|
|
### id: boot_logo
|
|
### resize: 200x200
|
|
### type: RGB565
|
|
### transparency: alpha_channel
|
|
## - file: mdi:fire
|
|
## id: icon_fire
|
|
## resize: 100x100
|
|
## type: BINARY
|
|
## - file: mdi:transmission-tower
|
|
## id: icon_utility
|
|
## resize: 80x80
|
|
## type: BINARY
|
|
##
|
|
##psram:
|
|
#
|
|
#sun:
|
|
# id: sun_sensor
|
|
# latitude: !secret latitude
|
|
# longitude: !secret longitude
|
|
#
|
|
##interval:
|
|
## - interval: 10s
|
|
## then:
|
|
## - canbus.send:
|
|
## canbus_id: canbus_sthome
|
|
## data: [0x48, 0x45, 0x4C, 0x4C, 0x4F]
|
|
## - lambda: |-
|
|
## ESP_LOGI("SND:${CB_CANBUS_ID9}", "HELLO");
|
|
#
|
|
#spi:
|
|
# - id: spi_bus0
|
|
# clk_pin: GPIO18
|
|
# mosi_pin: GPIO23
|
|
# miso_pin: GPIO19
|
|
# interface: any
|
|
# - id: spi_bus1
|
|
# clk_pin: GPIO17
|
|
# mosi_pin: GPIO16
|
|
# miso_pin: GPIO25
|
|
# interface: any
|
|
#
|
|
##one_wire:
|
|
## - platform: gpio
|
|
## pin: GPIO4
|
|
## id: temperature_sensors
|
|
#
|
|
## CAN BUS
|
|
#canbus:
|
|
# - platform: mcp2515
|
|
# cs_pin: GPIO05
|
|
# spi_id: spi_bus1
|
|
# id: canbus_sthome
|
|
# mode: LISTENONLY
|
|
# can_id: ${CB_CANBUS_ID09}
|
|
# #mode: NORMAL #LISTENONLY
|
|
# bit_rate: 500KBPS
|
|
# on_frame:
|
|
# - can_id: 0
|
|
# can_id_mask: 0
|
|
# then:
|
|
# - lambda: |-
|
|
# id(dump_can_message).execute(x, can_id, remote_transmission_request);
|
|
# - can_id: ${CB_BATTERY_STATE}
|
|
# then:
|
|
# - lambda: |-
|
|
# auto value = static_cast<uint16_t>((x[1] << 8) + x[0]);
|
|
# id(battery_soc).publish_state(value);
|
|
# value = static_cast<uint16_t>((x[3] << 8) + x[2]);
|
|
# id(battery_soh).publish_state(value);
|
|
# - can_id: ${CB_BATTERY_STATUS}
|
|
# then:
|
|
# - lambda: |-
|
|
# float value = 0.01 * static_cast<int16_t>((x[1] << 8) + x[0]); // unit = 0.01V Voltage of single module or average module voltage of system
|
|
# // ESP_LOGW("REC: ${CB_BATTERY_STATUS}", "Voltage: %f", value);
|
|
# id(battery_system_voltage).publish_state(value);
|
|
# value = 0.1 * static_cast<int16_t>((x[3] << 8) + x[2]); // unit = 0.1A Module or system total current
|
|
# // ESP_LOGW("REC: ${CB_BATTERY_STATUS}", "Current: %f", value);
|
|
# id(battery_system_current).publish_state(value);
|
|
# value = 0.1 * static_cast<int16_t>((x[5] << 8) + x[4]); // unit = 0.1°C
|
|
# id(battery_average_cell_temperature).publish_state(value);
|
|
# - can_id: ${CB_BATTERY_LIMITS}
|
|
# then:
|
|
# - lambda: |-
|
|
# float value = 0.1 * ((x[1] << 8) + x[0]); // unit = 0.1V
|
|
# id(battery_charge_voltage_limit).publish_state(value);
|
|
# value = 0.1 * static_cast<int16_t>((x[3] << 8) + x[2]); // unit = 0.1A
|
|
# id(battery_charge_current_limit).publish_state(value);
|
|
# value = 0.1 * static_cast<int16_t>((x[5] << 8) + x[4]); // unit = 0.1A
|
|
# id(battery_discharge_current_limit).publish_state(value);
|
|
# - can_id: ${CB_BATTERY_FAULT}
|
|
# then:
|
|
# - lambda: |-
|
|
# char buffer[16];
|
|
# uint8_t protection1 = x[0];
|
|
# uint8_t protection2 = x[1];
|
|
# uint8_t alarm1 = x[2];
|
|
# uint8_t alarm2 = x[3];
|
|
# uint8_t module_numbers = x[4];
|
|
# char ch5 = x[5];
|
|
# char ch6 = x[6];
|
|
# id(battery_discharge_over_current).publish_state(protection1 & 0x80);
|
|
# id(battery_cell_under_temperature).publish_state(protection1 & 0x10);
|
|
# id(battery_cell_over_temperature).publish_state(protection1 & 0x08);
|
|
# id(battery_cell_or_module_under_voltage).publish_state(protection1 & 0x04);
|
|
# id(battery_cell_or_module_over_voltage).publish_state(protection1 & 0x02);
|
|
# id(battery_system_error).publish_state(protection2 & 0x8);
|
|
# id(battery_charge_over_current).publish_state(protection2 & 0x01);
|
|
# id(battery_discharge_high_current).publish_state(alarm1 & 0x80);
|
|
# id(battery_cell_low_temperature).publish_state(alarm1 & 0x10);
|
|
# id(battery_cell_high_temperature).publish_state(alarm1 & 0x08);
|
|
# id(battery_cell_or_module_low_voltage).publish_state(alarm1 & 0x04);
|
|
# id(battery_cell_or_module_high_voltage).publish_state(alarm1 & 0x02);
|
|
# id(battery_internal_communication_fail).publish_state(alarm2 & 0x8);
|
|
# id(battery_charge_high_current).publish_state(alarm2 & 0x01);
|
|
# snprintf(buffer, sizeof(buffer), "%d %c%c", module_numbers, ch5, ch6);
|
|
# id(battery_module_numbers).publish_state(buffer);
|
|
# - can_id: ${CB_BATTERY_REQUEST_FLAG}
|
|
# then:
|
|
# - lambda: |-
|
|
# uint8_t request_flag = x[0];
|
|
# id(battery_charge_enable).publish_state(request_flag & 0x80);
|
|
# id(battery_discharge_enable).publish_state(request_flag & 0x40);
|
|
# id(battery_request_force_charge1).publish_state(request_flag & 0x20);
|
|
# id(battery_request_force_charge2).publish_state(request_flag & 0x10);
|
|
# id(battery_request_full_charge).publish_state( request_flag & 0x08);
|
|
# - can_id: ${CB_BATTERY_MANUFACTURER}
|
|
# then:
|
|
# - lambda: |-
|
|
# std::string str(x.begin(), x.end());
|
|
# id(battery_manufacturer).publish_state(str);
|
|
#
|
|
## - can_id: ${CB_GEYSER_ENERGISED}
|
|
## then:
|
|
## - lvgl.widget.update:
|
|
## id: ind_geyser_on
|
|
## hidden: !lambda |-
|
|
## std::string on_state(x.begin(), x.end());
|
|
## //ESP_LOGI("REC:${CB_GEYSER_ENERGISED}", "GEYSER IS: %s", on_state.c_str());
|
|
## if(on_state == "ON") {
|
|
## id(g_geyser_heating_on) = true;
|
|
## return false; // not hidden
|
|
## }
|
|
## else if(on_state == "OFF") {
|
|
## id(g_geyser_heating_on) = false;
|
|
## return true; // hidden
|
|
## }
|
|
## //ESP_LOGW("REC:${CB_GEYSER_ENERGISED}", "Invalid ON/OFF value: %s", on_state.c_str());
|
|
## return true; // default
|
|
## - can_id: ${CB_UTILITY_POWER_ON}
|
|
## then:
|
|
## - lvgl.widget.update:
|
|
## id: ind_utility_on
|
|
## hidden: !lambda |-
|
|
## std::string on_state(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_UTILITY_POWER_ON}", "UTILITY IS: %s", on_state.c_str());
|
|
## if(on_state == "ON") {
|
|
## id(g_utility_on) = true;
|
|
## return false; // not hidden
|
|
## }
|
|
## else if(on_state == "OFF") {
|
|
## id(g_utility_on) = false;
|
|
## return true; // hidden
|
|
## }
|
|
## ESP_LOGW("REC:${CB_UTILITY_POWER_ON}", "Invalid ON/OFF value: %s", on_state.c_str());
|
|
## return true; // default
|
|
#
|
|
## - can_id: ${CB_GEYSER_TOP_TEMPERATURE}
|
|
## then:
|
|
## - lambda: |-
|
|
## id(update_temperature_display).execute(x, id(g_geyser_top_temperature), rect_gtoptemp, ind_utility_on, lbl_gtoptemp);
|
|
##
|
|
## - can_id: ${CB_GEYSER_BOTTOM_TEMPERATURE}
|
|
## then:
|
|
## - lambda: |-
|
|
## id(update_temperature_display).execute(x, id(g_geyser_bottom_temperature) , rect_gbottemp, ind_geyser_on, lbl_gbottemp);
|
|
##
|
|
## - can_id: ${CB_CANBUS_ID1}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID1}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID2}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID2}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID3}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID3}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID4}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID4}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID5}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID5}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID6}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID6}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID7}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID7}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID8}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID8}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID9}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID9}", "%s", &b[0] );
|
|
## - can_id: ${CB_CANBUS_ID10}
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## ESP_LOGI("REC:${CB_CANBUS_ID10}", "%s", &b[0] );
|
|
#
|
|
## - can_id: 0x402
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## //ESP_LOGI("canid 0x402", "%s", &b[0] );
|
|
## ESP_LOGI("RECEIVED: canid 0x402", "%s", b.c_str());
|
|
## - can_id: 0x400
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## //ESP_LOGI("canid 0x400", "%s", &b[0] );
|
|
## ESP_LOGI("RECEIVED: canid 0x400", "%s", b.c_str());
|
|
## - can_id: 0x401
|
|
## then:
|
|
## - lambda: |-
|
|
## std::string b(x.begin(), x.end());
|
|
## //ESP_LOGI("canid 0x401", "%s", &b[0] );
|
|
## ESP_LOGI("RECEIVED: canid 0x401", "%s", b.c_str());
|
|
#
|
|
##display:
|
|
## - platform: ili9xxx
|
|
## model: ili9488
|
|
## id: tft_display
|
|
## color_palette: 8BIT
|
|
## data_rate: 40MHz
|
|
## spi_id: spi_bus0
|
|
## cs_pin: GPIO15
|
|
## dc_pin: GPIO2
|
|
## reset_pin: GPIO27
|
|
## auto_clear_enabled: false
|
|
## update_interval: never
|
|
## invert_colors: false
|
|
## show_test_card: true
|
|
## transform:
|
|
## swap_xy: true # landscape
|
|
### mirror_x: true # landscape
|
|
## dimensions:
|
|
## height: 480
|
|
## width: 320
|
|
#
|
|
## Define a PWM output on the ESP32
|
|
#output:
|
|
# - platform: ledc
|
|
# pin: GPIO26
|
|
# id: backlight_pwm
|
|
#
|
|
## Define a monochromatic, dimmable light for the backlight
|
|
#light:
|
|
# - platform: monochromatic
|
|
# output: backlight_pwm
|
|
# name: "Display Backlight"
|
|
# id: back_light
|
|
# restore_mode: ALWAYS_ON
|
|
#
|
|
##touchscreen:
|
|
## platform: xpt2046
|
|
## id: touch_screen
|
|
## spi_id: spi_bus0
|
|
## cs_pin: GPIO33
|
|
## transform:
|
|
## swap_xy: true # landscape
|
|
## # mirror_y: true # portrait
|
|
## calibration:
|
|
## x_min: 231 #201 #281
|
|
## x_max: 3878 #3793 #3848
|
|
## y_min: 221 #228 #347
|
|
## y_max: 3861 #3914 #3878
|
|
##
|
|
##lvgl:
|
|
### color_depth: 16
|
|
### bg_color: 0x0F0F0F
|
|
## default_font: unscii_8
|
|
### align: center
|
|
## theme:
|
|
## button:
|
|
## bg_color: grey_light #0x2F8CD8
|
|
### bg_grad_color: 0x005782
|
|
### bg_grad_dir: VER
|
|
## bg_opa: COVER
|
|
## border_color: 0x0077b3
|
|
## border_width: 1
|
|
## text_color: 0xFFFFFF
|
|
## pressed: # set some button colors to be different in pressed state
|
|
## bg_color: 0x006699
|
|
## bg_grad_color: 0x00334d
|
|
## checked: # set some button colors to be different in checked state
|
|
## bg_color: 0x1d5f96
|
|
## bg_grad_color: 0x03324A
|
|
## text_color: 0xfff300
|
|
### switch:
|
|
### bg_color: 0xC0C0C0
|
|
### bg_grad_color: 0xb0b0b0
|
|
### bg_grad_dir: VER
|
|
### bg_opa: COVER
|
|
### checked:
|
|
### bg_color: 0x1d5f96
|
|
### bg_grad_color: 0x03324A
|
|
### bg_grad_dir: VER
|
|
### bg_opa: COVER
|
|
### knob:
|
|
### bg_color: 0xFFFFFF
|
|
### bg_grad_color: 0xC0C0C0
|
|
### bg_grad_dir: VER
|
|
### bg_opa: COVER
|
|
### slider:
|
|
### border_width: 1
|
|
### border_opa: 15%
|
|
### bg_color: 0xcccaca
|
|
### bg_opa: 15%
|
|
### indicator:
|
|
### bg_color: 0x1d5f96
|
|
### bg_grad_color: 0x03324A
|
|
### bg_grad_dir: VER
|
|
### bg_opa: COVER
|
|
### knob:
|
|
### bg_color: 0x2F8CD8
|
|
### bg_grad_color: 0x005782
|
|
### bg_grad_dir: VER
|
|
### bg_opa: COVER
|
|
### border_color: 0x0077b3
|
|
### border_width: 1
|
|
### text_color: 0xFFFFFF
|
|
## style_definitions:
|
|
## - id: header_footer
|
|
## bg_color: darkgrey #0x2F8CD8
|
|
## bg_opa: COVER
|
|
## border_opa: TRANSP
|
|
## radius: 0
|
|
## pad_all: 0
|
|
## pad_row: 0
|
|
## pad_column: 0
|
|
## border_color: 0x0077b3
|
|
## text_color: 0xFFFFFF
|
|
## width: 100%
|
|
## height: 30
|
|
### - id: clockdate_style
|
|
### text_font: montserrat_20 #roboto_20 #unscii_8
|
|
### text_align: center
|
|
### text_color: 0x000000
|
|
### radius: 4
|
|
### pad_all: 2
|
|
### - id: sty_calendar_small
|
|
### radius: 0
|
|
### pad_all: 0
|
|
### pad_row: 0
|
|
### pad_column: 0
|
|
### text_font: unscii_8
|
|
### shadow_opa: TRANSP
|
|
### text_color: black
|
|
### bg_color: white
|
|
### bg_opa: COVER
|
|
### border_color: grey_light
|
|
### border_width: 1
|
|
### border_opa: cover #TRANSP
|
|
### - id: sty_calendar_small_noborders
|
|
### radius: 0
|
|
### pad_all: 0
|
|
### pad_row: 0
|
|
### pad_column: 0
|
|
### text_font: unscii_8
|
|
### shadow_opa: TRANSP
|
|
### text_color: black
|
|
### bg_color: white
|
|
### bg_opa: COVER
|
|
### border_color: grey_light
|
|
### border_width: 0
|
|
### border_opa: cover #TRANSP
|
|
## displays:
|
|
## - tft_display
|
|
## buffer_size: 12%
|
|
## top_layer:
|
|
## widgets:
|
|
## - label:
|
|
## text: "\U0000F5A9" # "\uF1EB"
|
|
## id: lbl_hastatus
|
|
## hidden: true
|
|
## align: top_right
|
|
## x: -2
|
|
## y: 1
|
|
## text_font: font_icon_small #montserrat_16
|
|
## text_align: right
|
|
## text_color: 0x202020 # 0xFFFFFF
|
|
## - obj: # clipping rectangle
|
|
## x: 0 #15
|
|
## y: -24 #7
|
|
## pad_all: 0
|
|
## height: 90
|
|
## width: 65
|
|
## align: BOTTOM_RIGHT
|
|
## bg_color: 0x000000
|
|
## border_color: 0xFFFFFF
|
|
## border_width: 0
|
|
## radius: 0
|
|
## bg_opa: LV_OPA_TRANSP
|
|
## scrollbar_mode: "OFF"
|
|
## widgets:
|
|
## - image:
|
|
## id: ind_geyser_on
|
|
## align: CENTER #BOTTOM_RIGHT #TOP_RIGHT
|
|
## src: icon_fire
|
|
## image_recolor: RED
|
|
## image_recolor_opa: 100%
|
|
## x: 0 #15 #15
|
|
## y: 0 #-22 #7
|
|
## height: 100 #25
|
|
## width: 100 #25
|
|
## - obj: # clipping rectangle
|
|
## x: 0 #15
|
|
## y: 2 #-24 #7
|
|
## pad_all: 0
|
|
## height: 80
|
|
## width: 65
|
|
## align: TOP_LEFT
|
|
## bg_color: 0x000000
|
|
## border_color: 0xFFFFFF
|
|
## border_width: 0
|
|
## radius: 0
|
|
## bg_opa: LV_OPA_TRANSP
|
|
## scrollbar_mode: "OFF"
|
|
## widgets:
|
|
## - image:
|
|
## id: ind_utility_on
|
|
## align: CENTER #BOTTOM_RIGHT #TOP_RIGHT
|
|
## src: icon_utility
|
|
## image_recolor: grey #!lambda 'return lv_color_hex(0x000000);'
|
|
## image_recolor_opa: 100%
|
|
## x: 0 #15 #15
|
|
## y: 0 #-22 #7
|
|
## height: 80 #25
|
|
## width: 80 #25
|
|
### - obj:
|
|
### id: boot_screen
|
|
### x: 0
|
|
### y: 0
|
|
### width: 100%
|
|
### height: 100%
|
|
### bg_color: 0xffffff
|
|
### bg_opa: COVER
|
|
### radius: 0
|
|
### pad_all: 0
|
|
### border_width: 0
|
|
### widgets:
|
|
### - image:
|
|
### align: CENTER
|
|
### src: boot_logo
|
|
### y: -40
|
|
### - spinner:
|
|
### align: CENTER
|
|
### y: 95
|
|
### height: 50
|
|
### width: 50
|
|
### spin_time: 1s
|
|
### arc_length: 60deg
|
|
### arc_width: 8
|
|
### indicator:
|
|
### arc_color: 0x18bcf2
|
|
### arc_width: 8
|
|
### on_press:
|
|
### - lvgl.widget.hide: boot_screen
|
|
## - buttonmatrix:
|
|
## text_font: montserrat_16
|
|
## align: bottom_mid
|
|
## styles: header_footer
|
|
## pad_all: 0
|
|
## outline_width: 0
|
|
## id: footer
|
|
## width: 480
|
|
## items:
|
|
## styles: header_footer
|
|
## rows:
|
|
## - buttons:
|
|
## - id: page_prev
|
|
## text: "\uF053"
|
|
## on_press:
|
|
## then:
|
|
## lvgl.page.previous:
|
|
## - id: page_home
|
|
## text: "\uF015"
|
|
## on_press:
|
|
## then:
|
|
## lvgl.page.show: main_page
|
|
## - id: page_next
|
|
## text: "\uF054"
|
|
## on_press:
|
|
## then:
|
|
## lvgl.page.next:
|
|
## pages:
|
|
## # - id: pg_calendar
|
|
## # widgets:
|
|
## # - button:
|
|
## # id: cal_btn_prev_month
|
|
## # styles: sty_calendar_small
|
|
## # align: TOP_MID
|
|
## # pad_all: 0
|
|
## # outline_width: 0
|
|
## # border_color: black
|
|
## # border_width: 0 #1
|
|
## # border_opa: TRANSP
|
|
## # x: -75
|
|
## # y: 30
|
|
## # width: 20
|
|
## # height: 20
|
|
## # bg_color: grey_light
|
|
## # text_color: 0xD3D3D3
|
|
## # text_font: montserrat_14
|
|
## # widgets:
|
|
## # - label:
|
|
## # align: center
|
|
## # text_font: montserrat_14
|
|
## # text: "<"
|
|
## # on_press:
|
|
## # then:
|
|
## # lambda: |-
|
|
## # id(update_calendar_month).execute(-1);
|
|
## # - dropdown:
|
|
## # id: cal_dd_year
|
|
## # styles: sty_calendar_small
|
|
## # text_font: montserrat_12
|
|
## # height: 20
|
|
## # width: 55
|
|
## # radius: 0
|
|
## # align_to:
|
|
## # id: cal_btn_prev_month
|
|
## # align: out_right_top
|
|
## # x: 80
|
|
## # y: 0 #12.5%
|
|
## # options:
|
|
## # - 2024
|
|
## # - 2025
|
|
## # selected_index: 0
|
|
## # dropdown_list:
|
|
## # text_line_space: 3
|
|
## # pad_all: 1
|
|
## # text_font: unscii_8
|
|
## # max_height: 260
|
|
## # radius: 0
|
|
## # selected:
|
|
## # checked:
|
|
## # text_color: 0xFF0000
|
|
## # on_value:
|
|
## # then:
|
|
## # - lambda: |-
|
|
## # id(update_calendar).execute();
|
|
## # - dropdown:
|
|
## # id: cal_dd_month
|
|
## # styles: sty_calendar_small
|
|
## # text_font: montserrat_12
|
|
## # height: 20
|
|
## # width: 55
|
|
## # radius: 0
|
|
## # align_to:
|
|
## # id: cal_dd_year
|
|
## # align: out_right_top
|
|
## # x: 0
|
|
## # y: 0 #12.5%
|
|
## # options:
|
|
## # - Jan
|
|
## # - Feb
|
|
## # - Mar
|
|
## # - Apr
|
|
## # - May
|
|
## # - Jun
|
|
## # - Jul
|
|
## # - Aug
|
|
## # - Sep
|
|
## # - Oct
|
|
## # - Nov
|
|
## # - Dec
|
|
## # selected_index: 0
|
|
## # dropdown_list:
|
|
## # text_line_space: 3
|
|
## # pad_all: 1
|
|
## # text_font: unscii_8
|
|
## # max_height: 260
|
|
## # radius: 0
|
|
## # selected:
|
|
## # checked:
|
|
## # text_color: 0xFF0000
|
|
## # on_value:
|
|
## # then:
|
|
## # - lambda: |-
|
|
## # id(update_calendar).execute();
|
|
## # - button:
|
|
## # id: cal_btn_next_month
|
|
## # styles: sty_calendar_small
|
|
## # align_to:
|
|
## # id: cal_dd_month
|
|
## # align: out_right_top
|
|
## # x: 0
|
|
## # y: 0
|
|
## # pad_all: 0
|
|
## # outline_width: 0
|
|
## # border_color: black
|
|
## # border_width: 0 #1
|
|
## # border_opa: TRANSP
|
|
## # x: -75
|
|
## # y: 30
|
|
## # width: 20
|
|
## # height: 20
|
|
## # bg_color: grey_light
|
|
## # text_color: 0xD3D3D3
|
|
## # text_font: montserrat_14
|
|
## # widgets:
|
|
## # - label:
|
|
## # align: center
|
|
## # text_font: montserrat_14
|
|
## # text: ">"
|
|
## # on_press:
|
|
## # then:
|
|
## # lambda: |-
|
|
## # id(update_calendar_month).execute(1);
|
|
## # - buttonmatrix:
|
|
## # id: bmx_cal_header_dow
|
|
## # styles: sty_calendar_small_noborders
|
|
## # align_to:
|
|
## # id: cal_btn_prev_month
|
|
## # align: out_bottom_left
|
|
## # x: 80
|
|
## # y: 0 #12.5%
|
|
## # pad_all: 0
|
|
## # outline_width: 0
|
|
## # border_color: black
|
|
## # border_width: 0 #1
|
|
## # border_opa: TRANSP
|
|
## # x: 0
|
|
## # y: 0
|
|
## # width: 150
|
|
## # height: 20
|
|
## # bg_color: black
|
|
## # text_color: 0xD3D3D3
|
|
## # items:
|
|
## # styles: sty_calendar_small_noborders
|
|
## # pressed:
|
|
## # bg_color: 0x006699
|
|
## # bg_grad_color: 0x00334d
|
|
## # checked:
|
|
## # bg_color: 0x1d5f96
|
|
## # bg_grad_color: 0x03324A
|
|
## # rows:
|
|
## # - buttons:
|
|
## # - id: r0c1
|
|
## # text: "Su"
|
|
## # width: 1
|
|
## # - id: r0c2
|
|
## # text: "Mo"
|
|
## # width: 1
|
|
## # - id: r0c3
|
|
## # text: "Tu"
|
|
## # width: 1
|
|
## # - id: r0c4
|
|
## # text: "We"
|
|
## # width: 1
|
|
## # - id: r0c5
|
|
## # text: "Th"
|
|
## # width: 1
|
|
## # - id: r0c6
|
|
## # text: "Fr"
|
|
## # width: 1
|
|
## # - id: r0c7
|
|
## # text: "Sa"
|
|
## # width: 1
|
|
## # on_press:
|
|
## # then:
|
|
## # - lambda: |-
|
|
## # ESP_LOGI("day of week", "%d", x);
|
|
## # - buttonmatrix:
|
|
## # id: bmx_calendar
|
|
## # styles: sty_calendar_small
|
|
## # align_to:
|
|
## # id: bmx_cal_header_dow
|
|
## # align: out_bottom_left
|
|
## # x: 0
|
|
## # y: 0 #12.5%
|
|
## # pad_all: 0
|
|
## # outline_width: 0
|
|
## # border_color: black
|
|
## # border_width: 0 #1
|
|
## # border_opa: TRANSP
|
|
## # x: 0
|
|
## # y: 0
|
|
## # width: 150
|
|
## # height: 100
|
|
## # bg_color: black
|
|
## # text_color: 0xD3D3D3
|
|
## # items:
|
|
## # styles: sty_calendar_small
|
|
## # pressed:
|
|
## # bg_color: 0x006699
|
|
## # bg_grad_color: 0x00334d
|
|
## # checked:
|
|
## # bg_color: 0x1d5f96
|
|
## # bg_grad_color: 0x03324A
|
|
## # rows:
|
|
## # - buttons:
|
|
## # - id: r1c1
|
|
## # text: " "
|
|
## # width: 1
|
|
## # control:
|
|
## # recolor: true
|
|
## # - id: r1c2
|
|
## # text: " "
|
|
## # width: 1
|
|
## # - id: r1c3
|
|
## # text: "1"
|
|
## # width: 1
|
|
## # - id: r1c4
|
|
## # text: "2"
|
|
## # width: 1
|
|
## # - id: r1c5
|
|
## # text: "3"
|
|
## # width: 1
|
|
## # - id: r1c6
|
|
## # text: "4"
|
|
## # width: 1
|
|
## # - id: r1c7
|
|
## # text: "5"
|
|
## # width: 1
|
|
##
|
|
## # # Define actions on button press
|
|
## # on_press:
|
|
## # then:
|
|
## # lambda: |-
|
|
## # //lv_btnmatrix_set_btn_ctrl_all(bmx_calendar->obj, LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_RECOLOR);
|
|
## # //lv_btnmatrix_set_one_checked(bmx_calendar->obj, false);
|
|
## # //id(get_calendar_days_state).execute("P1");
|
|
## # //auto stat = lv_btnmatrix_has_btn_ctrl(bmx_calendar->obj, x, LV_BTNMATRIX_CTRL_CHECKED);
|
|
## # //ESP_LOGI("on press", "day: %s, stat: %d", lv_btnmatrix_get_btn_text(bmx_calendar->obj, x), stat);
|
|
## # //id(get_calendar_days_state).execute("P2");
|
|
## # on_release:
|
|
## # then:
|
|
## # lambda: |-
|
|
## # id(get_calendar_days_state).execute("R1");
|
|
## # //auto stat = lv_btnmatrix_has_btn_ctrl(bmx_calendar->obj, x, LV_BTNMATRIX_CTRL_CHECKED);
|
|
## # //auto* day = lv_btnmatrix_get_btn_text(bmx_calendar->obj, x);
|
|
## # // if(stat) {
|
|
## # // lv_btnmatrix_clear_btn_ctrl(bmx_calendar->obj, x, LV_BTNMATRIX_CTRL_CHECKED);
|
|
## # // }
|
|
## # // else {
|
|
## # // lv_btnmatrix_set_btn_ctrl(bmx_calendar->obj, x, LV_BTNMATRIX_CTRL_CHECKED);
|
|
## # // }
|
|
## # //auto stat = lv_btnmatrix_has_btn_ctrl(bmx_calendar->obj, x, LV_BTNMATRIX_CTRL_CHECKED);
|
|
## # //ESP_LOGI("on relse", "day: %s, stat: %d", lv_btnmatrix_get_btn_text(bmx_calendar->obj, x), stat);
|
|
## # //id(get_calendar_days_state).execute("R2");
|
|
##
|
|
## - id: main_page #pg_geyser_temp
|
|
## widgets:
|
|
## - obj:
|
|
## id: rect_gtoptemp
|
|
## x: 0
|
|
## y: 0 #30
|
|
## pad_all: 0
|
|
## height: 290
|
|
## width: 240
|
|
## align: TOP_LEFT
|
|
## bg_color: 0x000000
|
|
## border_color: 0xFFFFFF
|
|
## border_width: 0
|
|
## radius: 0
|
|
## bg_opa: COVER
|
|
## - obj:
|
|
## id: rect_gbottemp
|
|
## y: 0
|
|
## pad_all: 0
|
|
## height: 290
|
|
## width: 240
|
|
## align_to:
|
|
## id: rect_gtoptemp
|
|
## align: out_right_top
|
|
## x: 0
|
|
## y: 0 #12.5%
|
|
## bg_color: 0x000000 #0xFF4500
|
|
## border_color: 0xFFFFFF
|
|
## border_width: 0
|
|
## radius: 0
|
|
## bg_opa: COVER
|
|
## - label:
|
|
## text: " "
|
|
## id: lbl_gtoptemp
|
|
## hidden: false
|
|
## align: LEFT_MID
|
|
## x: 0
|
|
## y: -10
|
|
## text_font: roboto_200
|
|
## text_align: center
|
|
## text_color: 0x0
|
|
## bg_opa: LV_OPA_TRANSP
|
|
## bg_color: 0xffffff
|
|
## - label:
|
|
## text: " "
|
|
## id: lbl_gbottemp
|
|
## hidden: false
|
|
## align: RIGHT_MID
|
|
## x: 0
|
|
## y: -10
|
|
## text_font: roboto_200
|
|
## text_align: center
|
|
## text_color: 0x0
|
|
## bg_opa: LV_OPA_TRANSP
|
|
## bg_color: 0xffffff
|
|
### - label:
|
|
### text: "°C"
|
|
### id: lbl_degree
|
|
### hidden: false
|
|
### align: BOTTOM_MID
|
|
### x: 0
|
|
### y: -30
|
|
### text_font: geyser_temperature_font2
|
|
### text_align: center
|
|
### text_color: 0x0
|
|
### bg_opa: LV_OPA_TRANSP
|
|
### bg_color: 0xffffff
|
|
## - label:
|
|
## text: "top"
|
|
## id: lbl_top
|
|
## hidden: false
|
|
## align: TOP_MID
|
|
## x: -120
|
|
## y: 20
|
|
## text_font: geyser_temperature_font3
|
|
## text_align: center
|
|
## text_color: 0x0
|
|
## bg_opa: LV_OPA_TRANSP
|
|
## bg_color: 0xffffff
|
|
## - label:
|
|
## text: "bottom"
|
|
## id: lbl_bottom
|
|
## hidden: false
|
|
## align: TOP_MID
|
|
## x: 120
|
|
## y: 20
|
|
## text_font: geyser_temperature_font3
|
|
## text_align: center
|
|
## text_color: 0x0
|
|
## bg_opa: LV_OPA_TRANSP
|
|
## bg_color: 0xffffff
|
|
##
|
|
### - id: pg_settings
|
|
### widgets:
|
|
### - textarea:
|
|
### id: geyser_schedule
|
|
### one_line: true
|
|
### placeholder_text: "Enter text here"
|
|
### - keyboard:
|
|
### id: keyboard_id
|
|
### textarea: geyser_schedule
|
|
### mode: TEXT_UPPER
|
|
### text_font: montserrat_20
|
|
### on_focus:
|
|
### then:
|
|
### - lvgl.keyboard.update:
|
|
### id: keyboard_id
|
|
### mode: number
|
|
### textarea: geyser_schedule
|
|
### on_ready:
|
|
### then:
|
|
### - logger.log: Keyboard is ready
|
|
### on_cancel:
|
|
### then:
|
|
### - logger.log: Keyboard cancelled#
|
|
##
|
|
### - id: pg_clock
|
|
### widgets:
|
|
### - obj: # clock container
|
|
### height: 300 #SIZE_CONTENT
|
|
### width: 300 # 100%
|
|
### align: TOP_MID
|
|
### pad_all: 0
|
|
### border_width: 0
|
|
### bg_color: 0xFFFFFF
|
|
### widgets:
|
|
### - meter: # clock face
|
|
### height: 300
|
|
### width: 300
|
|
### align: TOP_MID
|
|
### bg_opa: TRANSP
|
|
### border_width: 0
|
|
### text_color: 0x000000
|
|
### scales:
|
|
### - range_from: 0 # minutes scale
|
|
### range_to: 720
|
|
### angle_range: 360
|
|
### rotation: 270
|
|
### ticks:
|
|
### width: 1
|
|
### count: 61
|
|
### length: 10
|
|
### color: 0x000000
|
|
### indicators:
|
|
### - line:
|
|
### id: minute_hand
|
|
### width: 3
|
|
### color: 0xa6a6a6
|
|
### r_mod: -4
|
|
### value: 0
|
|
### - range_from: 1 # hours scale for labels
|
|
### range_to: 12
|
|
### angle_range: 330
|
|
### rotation: 300
|
|
### ticks:
|
|
### width: 1
|
|
### count: 12
|
|
### length: 1
|
|
### major:
|
|
### stride: 1
|
|
### width: 4
|
|
### length: 10
|
|
### color: 0xC0C0C0
|
|
### label_gap: 12
|
|
### - range_from: 0 # hi-res hours scale for hand
|
|
### range_to: 720
|
|
### angle_range: 360
|
|
### rotation: 270
|
|
### ticks:
|
|
### count: 0
|
|
### indicators:
|
|
### - line:
|
|
### id: hour_hand
|
|
### width: 5
|
|
### color: 0xa6a6a6
|
|
### r_mod: -30
|
|
### value: 0
|
|
### # Second hand
|
|
### - angle_range: 360
|
|
### rotation: 270
|
|
### range_from: 0
|
|
### range_to: 60
|
|
### indicators:
|
|
### - line:
|
|
### id: second_hand
|
|
### width: 2
|
|
### color: Red
|
|
### r_mod: -10
|
|
### - label:
|
|
### align: CENTER
|
|
### styles: clockdate_style
|
|
### id: day_label
|
|
### y: -50
|
|
### - label:
|
|
### align: CENTER
|
|
### id: date_label
|
|
### styles: clockdate_style
|
|
### y: 50
|
|
##
|
|
### - id: pg_digital_clock
|
|
### widgets:
|
|
### - obj:
|
|
### id: rect_gtoptemp1
|
|
### x: 0
|
|
### y: 0 #30
|
|
### pad_all: 0
|
|
### height: 290
|
|
### width: 240
|
|
### align: TOP_LEFT
|
|
### bg_color: 0x000000
|
|
### border_color: 0xFFFFFF
|
|
### border_width: 0
|
|
### radius: 0
|
|
### bg_opa: COVER
|
|
### - obj:
|
|
### id: rect_gbottemp1
|
|
### y: 0
|
|
### pad_all: 0
|
|
### height: 290
|
|
### width: 240
|
|
### align_to:
|
|
### id: rect_gtoptemp
|
|
### align: out_right_top
|
|
### x: 0
|
|
### y: 0 #12.5%
|
|
### bg_color: 0x000000 #0xFF4500
|
|
### border_color: 0xFFFFFF
|
|
### border_width: 0
|
|
### radius: 0
|
|
### bg_opa: COVER
|
|
### - label:
|
|
### text: " "
|
|
### id: lbl_digitalclock
|
|
### hidden: false
|
|
### align: TOP_MID
|
|
### x: 0
|
|
### y: 20
|
|
### text_font: roboto_192
|
|
### text_align: center
|
|
### text_color: RED
|
|
### bg_opa: LV_OPA_TRANSP
|
|
### bg_color: 0xffffff
|
|
##
|
|
##switch:
|
|
## - platform: restart
|
|
## name: "${name} Restart"
|
|
## id: "restart_switch"
|
|
### - platform: template
|
|
### name: Antiburn
|
|
### id: switch_antiburn
|
|
### icon: mdi:television-shimmer
|
|
### optimistic: true
|
|
### entity_category: "config"
|
|
### turn_on_action:
|
|
### - logger.log: "Starting Antiburn"
|
|
### - if:
|
|
### condition: lvgl.is_paused
|
|
### then:
|
|
### - lvgl.resume:
|
|
### - lvgl.widget.redraw:
|
|
### - lvgl.pause:
|
|
### show_snow: true
|
|
### turn_off_action:
|
|
### - logger.log: "Stopping Antiburn"
|
|
### - if:
|
|
### condition: lvgl.is_paused
|
|
### then:
|
|
### - lvgl.resume:
|
|
### - lvgl.widget.redraw:
|
|
#
|
|
# binary_sensor:
|
|
# - platform: template
|
|
# id: battery_discharge_over_current
|
|
# name: "Battery Discharge Over Current"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_cell_under_temperature
|
|
# name: "Battery Cell Under Temperature"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_cell_over_temperature
|
|
# name: "Battery Cell Over Temperature"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_cell_or_module_under_voltage
|
|
# name: "Battery Under Voltage"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_cell_or_module_over_voltage
|
|
# name: "Battery Over Voltage"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_system_error
|
|
# name: "Battery System Error"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_charge_over_current
|
|
# name: "Battery Charge Over Current"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_discharge_high_current
|
|
# name: "Battery Discharge High Current"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_cell_low_temperature
|
|
# name: "Battery Low Temperature"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_cell_high_temperature
|
|
# name: "Battery High Temperature"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_cell_or_module_low_voltage
|
|
# name: "Battery Low Voltage"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_cell_or_module_high_voltage
|
|
# name: "Battery High Voltage"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_internal_communication_fail
|
|
# name: "Battery Communication Fail"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_charge_high_current
|
|
# name: "Battery Charge High Current"
|
|
# device_class: problem
|
|
# - platform: template
|
|
# id: battery_charge_enable
|
|
# name: "Battery Charge Enable"
|
|
# #device_class: battery_charging
|
|
# - platform: template
|
|
# id: battery_discharge_enable
|
|
# name: "Battery Discharge Enable"
|
|
# #device_class: battery_charging
|
|
# - platform: template
|
|
# id: battery_request_force_charge1
|
|
# name: "Battery Request Force Charge 1"
|
|
# # device_class: battery_charging
|
|
# - platform: template
|
|
# id: battery_request_force_charge2
|
|
# name: "Battery Request Force Charge 2"
|
|
# # device_class: battery_charging
|
|
# - platform: template
|
|
# id: battery_request_full_charge
|
|
# name: "Battery Request Full Charge "
|
|
# # device_class: battery_charging
|
|
# - platform: template
|
|
# id: battery_charging
|
|
# name: "Battery Charging"
|
|
# device_class: battery_charging
|
|
# lambda: "return id(battery_system_current).state > 0;"
|
|
#
|
|
#sensor:
|
|
# - platform: template
|
|
# id: battery_soc
|
|
# name: "Battery SOC"
|
|
# accuracy_decimals: 0
|
|
# unit_of_measurement: "%"
|
|
# state_class: measurement
|
|
# device_class: battery
|
|
# - platform: template
|
|
# id: battery_soh
|
|
# name: "Battery SOH"
|
|
# accuracy_decimals: 0
|
|
# unit_of_measurement: "%"
|
|
# state_class: measurement
|
|
# device_class: battery
|
|
# - platform: template
|
|
# id: battery_system_voltage
|
|
# name: "Battery Voltage"
|
|
# accuracy_decimals: 2
|
|
# unit_of_measurement: "V"
|
|
# state_class: measurement
|
|
# device_class: voltage
|
|
# - platform: template
|
|
# id: battery_system_current
|
|
# name: "Battery Current"
|
|
# accuracy_decimals: 1
|
|
# unit_of_measurement: "A"
|
|
# state_class: measurement
|
|
# device_class: current
|
|
# - platform: template
|
|
# id: battery_average_cell_temperature
|
|
# name: "Battery Cell Temperature"
|
|
# accuracy_decimals: 1
|
|
# unit_of_measurement: "°C"
|
|
# device_class: temperature
|
|
# state_class: measurement
|
|
# - platform: template
|
|
# id: battery_charge_voltage_limit
|
|
# name: "Battery Charge Voltage Limit"
|
|
# accuracy_decimals: 1
|
|
# unit_of_measurement: "V"
|
|
# state_class: measurement
|
|
# device_class: voltage
|
|
# - platform: template
|
|
# id: battery_charge_current_limit
|
|
# name: "Battery Charge Current Limit"
|
|
# accuracy_decimals: 1
|
|
# unit_of_measurement: "A"
|
|
# state_class: measurement
|
|
# device_class: current
|
|
# - platform: template
|
|
# id: battery_discharge_current_limit
|
|
# name: "Battery Discharge Current Limit"
|
|
# accuracy_decimals: 1
|
|
# unit_of_measurement: "A"
|
|
# state_class: measurement
|
|
# device_class: current
|
|
#
|
|
#
|
|
## - platform: dallas_temp
|
|
## address: 0xfe00000037b3d528
|
|
## name: "Study Temperature"
|
|
## id: study_temperature
|
|
## update_interval: "60s"
|
|
## resolution: 12
|
|
## one_wire_id: temperature_sensors
|
|
## unit_of_measurement: "°C"
|
|
## #icon: "mdi:water-thermometer"
|
|
## device_class: "temperature"
|
|
## state_class: "measurement"
|
|
## accuracy_decimals: 1
|
|
## filters:
|
|
## - filter_out: nan
|
|
## # - sliding_window_moving_average:
|
|
## # window_size: 120 # averages over 120 update intervals
|
|
## # send_every: 60 # reports every 60 update intervals
|
|
#
|
|
# # Report wifi signal strength every 5 min if changed
|
|
# - platform: wifi_signal
|
|
# name: WiFi Signal
|
|
# id: wifi_sig
|
|
# update_interval: 300s
|
|
# filters:
|
|
# - delta: 10%
|
|
#
|
|
# # 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();
|
|
##
|
|
### number of seconds since midnight
|
|
## - platform: template
|
|
## id: time_of_day
|
|
## name: "Time of day"
|
|
## accuracy_decimals: 0
|
|
## unit_of_measurement: "s"
|
|
## lambda: |-
|
|
## auto currenttime = id(time_source).now();
|
|
## ESPTime time_obj = currenttime;
|
|
## time_obj.second = 0;
|
|
## time_obj.minute = 0;
|
|
## time_obj.hour = 0;
|
|
## time_obj.recalc_timestamp_local();
|
|
## return currenttime.timestamp - time_obj.timestamp;
|
|
## update_interval: 60s
|
|
#
|
|
#text_sensor:
|
|
### - platform: template
|
|
### id: module_time
|
|
### name: "Module time"
|
|
### icon: mdi:clock
|
|
### lambda: |-
|
|
### auto time_obj = id(time_source).now();
|
|
### return time_obj.strftime("%Y-%m-%d %H:%M:%S");
|
|
### update_interval: 60s
|
|
##
|
|
## # Expose WiFi information as sensors
|
|
## - platform: wifi_info
|
|
## ip_address:
|
|
## name: IP
|
|
## mac_address:
|
|
## name: Mac Address
|
|
## entity_category: diagnostic
|
|
## ssid:
|
|
## name: "Connected SSID"
|
|
## id: ssid
|
|
## entity_category: diagnostic
|
|
##
|
|
## # human readable update text sensor from sensor:uptime
|
|
## - platform: template
|
|
## name: Uptime
|
|
## id: uptime_human
|
|
## icon: mdi:clock-start
|
|
##
|
|
## - platform: template
|
|
## name: 'Last Restart'
|
|
## id: device_last_restart
|
|
## icon: mdi:clock
|
|
## entity_category: diagnostic
|
|
# - platform: template
|
|
# id: battery_manufacturer
|
|
# name: "Battery Manufacturer"
|
|
# - platform: template
|
|
# id: battery_module_numbers
|
|
# name: "Battery Module Numbers"
|
|
#
|
|
#script:
|
|
## - id: update_temperature_display
|
|
## parameters:
|
|
## x: std::vector<uint8_t>&
|
|
## globalvar: double&
|
|
## rect: lv_obj_t*
|
|
## indicator: lv_obj_t*
|
|
## label: lv_obj_t*
|
|
## then:
|
|
## - lambda: |-
|
|
## char buffer [4];
|
|
## buffer[0] = '\0';
|
|
## double value = x[3] + ((double)((x[2] << 16) + (x[1] << 8) + x[0]))/16777216;
|
|
## globalvar = value;
|
|
## snprintf (buffer, 4, "%.0f", value);
|
|
## auto bgcolor = lv_color_hex(0xFF0000);
|
|
## auto ind_color = lv_color_hex(0xFF0000);
|
|
## if(value < 40) {
|
|
## bgcolor = lv_color_hex(0x0000FF);
|
|
## }
|
|
## else if(value < 50) {
|
|
## bgcolor = lv_color_hex(0x00FF00);
|
|
## }
|
|
## else if(value < 60) {
|
|
## bgcolor = lv_color_hex(0xFFFF00);
|
|
## }
|
|
## else {
|
|
## ind_color = lv_color_hex(0xFFFF00); // make different to bgcolor
|
|
## }
|
|
## lv_obj_set_style_bg_color(rect, bgcolor, LV_PART_MAIN);
|
|
## lv_obj_set_style_img_recolor(indicator, ind_color, LV_PART_MAIN);
|
|
## lv_label_set_text(label, buffer);
|
|
#
|
|
## - id: time_update
|
|
## then:
|
|
## - lvgl.indicator.update:
|
|
## id: minute_hand
|
|
## value: !lambda |-
|
|
## auto now = id(time_source).now();
|
|
## return now.minute * 12 + now.second/5;
|
|
## - lvgl.indicator.update:
|
|
## id: hour_hand
|
|
## value: !lambda |-
|
|
## auto now = id(time_source).now();
|
|
## return std::fmod(now.hour, 12) * 60 + now.minute;
|
|
## - lvgl.indicator.update:
|
|
## id: second_hand
|
|
## value: !lambda |-
|
|
## auto now = id(time_source).now();
|
|
## return now.second;
|
|
## - lvgl.label.update:
|
|
## id: date_label
|
|
## text: !lambda |-
|
|
## static const char * const mon_names[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
|
|
## static char date_buf[8];
|
|
## auto now = id(time_source).now();
|
|
## snprintf(date_buf, sizeof(date_buf), "%s %2d", mon_names[now.month-1], now.day_of_month);
|
|
## return date_buf;
|
|
## - lvgl.label.update:
|
|
## id: day_label
|
|
## text: !lambda |-
|
|
## static const char * const day_names[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
|
|
## return day_names[id(time_source).now().day_of_week - 1];
|
|
## - lvgl.label.update:
|
|
## id: lbl_digitalclock
|
|
## text: !lambda |-
|
|
## auto time_obj = id(time_source).now();
|
|
## return time_obj.strftime("%H:%M");
|
|
#
|
|
## - id: ind_heating_update
|
|
## then:
|
|
## - lvgl.widget.update:
|
|
## id: ind_geyser_on
|
|
## hidden: !lambda return !id(g_geyser_heating_on);
|
|
#
|
|
## - id: init_calendar
|
|
## then:
|
|
## - lambda: |-
|
|
## auto now = id(time_source).now();
|
|
## //ESP_LOGI("yopts before", stroptions.c_str());
|
|
## int y = 0;
|
|
## std::string stroptions = to_string(now.year + y);
|
|
## while(++y < ${DD_MAX_YEARS}) {
|
|
## stroptions += "\n" + to_string(now.year + y);
|
|
## }
|
|
## //ESP_LOGI("yopts after", stroptions.c_str());
|
|
## lv_dropdown_set_options(cal_dd_year->obj, stroptions.c_str());
|
|
## lv_dropdown_set_selected(cal_dd_year->obj, 0); // this year is first index
|
|
## lv_dropdown_set_selected(cal_dd_month->obj, now.month-1);
|
|
## id(g_year_idx) = 0;
|
|
## id(update_calendar).execute();
|
|
## lv_btnmatrix_set_btn_ctrl_all(bmx_calendar->obj, LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_RECOLOR);
|
|
#
|
|
## - id: update_calendar_month
|
|
## parameters:
|
|
## increment : int
|
|
## then:
|
|
## - lambda: |-
|
|
## char yearstr[8];
|
|
## lv_dropdown_get_selected_str(cal_dd_year->obj, yearstr, sizeof(yearstr));
|
|
## auto year = atoi(yearstr);
|
|
## int year_idx = lv_dropdown_get_selected(cal_dd_year->obj);
|
|
## int month_idx = increment + lv_dropdown_get_selected(cal_dd_month->obj);
|
|
## int month = 1 + month_idx;
|
|
## if(month > 12 && year_idx < ${DD_MAX_YEARS} - 1) {
|
|
## month -= 12;
|
|
## month_idx -= 12;
|
|
## year++;
|
|
## year_idx++;
|
|
## }
|
|
## else if(month < 1 && year_idx > 0) {
|
|
## month += 12;
|
|
## month_idx += 12;
|
|
## year--;
|
|
## year_idx--;
|
|
## }
|
|
## ESP_LOGI("cm", "month: %d, year: %d", month, year);
|
|
## if(month < 13 && month > 0) {
|
|
## lv_dropdown_set_selected(cal_dd_year->obj, year_idx);
|
|
## lv_dropdown_set_selected(cal_dd_month->obj, month_idx);
|
|
## id(g_year_idx) = year_idx;
|
|
## id(update_calendar).execute();
|
|
## }
|
|
##
|
|
## - id: update_calendar
|
|
## then:
|
|
## lambda: |-
|
|
## char yearstr[8];
|
|
## int monthdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
## static std::string strdays[44];
|
|
## static const char *pstrdays[49]; // including newline at end of week
|
|
## static const char *newline = "\n";
|
|
## id(persist_calendar).execute();
|
|
## lv_dropdown_get_selected_str(cal_dd_year->obj, yearstr, sizeof(yearstr));
|
|
## int year = atoi(yearstr);
|
|
## int month = 1 + lv_dropdown_get_selected(cal_dd_month->obj);
|
|
## bool isLeapYear = (year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0));
|
|
## monthdays[1] = (isLeapYear) ? 29 : 28;
|
|
## // calculate day of week of 1st of month using Zeller's rule
|
|
## // https://beginnersbook.com/2013/04/calculating-day-given-date
|
|
## // modified month, year
|
|
## int mM = month - 2;
|
|
## int m = mM < 1 ? 12 + mM : mM;
|
|
## int mY = mM < 1 ? year - 1 : year;
|
|
## int k = 1; // day of month
|
|
## int D = mY % 100; // last two digits of the year
|
|
## int C = trunc(mY / 100); // first two digits of the year
|
|
## int F = k + trunc((13 * m - 1) / 5) + D + trunc(D / 4) + trunc(C / 4) - 2 * C;
|
|
## int Z = F % 7;
|
|
## int start_of_month = Z < 0 ? Z + 7 : Z;
|
|
## // end of Zeller's rule
|
|
## int previous_month = (month == 1) ? 12 : month - 1;
|
|
## int month_days = monthdays[month - 1];
|
|
## int prev_month_days = monthdays[previous_month - 1];
|
|
## int i = 0;
|
|
## int j = -1;
|
|
## //ESP_LOGI("vals", "start_of_month: %d, previous_month: %d, month_days: %d, prev_month_days: %d", start_of_month, previous_month, month_days, prev_month_days);
|
|
## for (int w = 0; w < 6 && i < (month_days + start_of_month); w++) {
|
|
## for(int wd = 0; wd < 7; wd++) {
|
|
## int day = i + 1 - start_of_month;
|
|
## if (i < start_of_month) {
|
|
## day += prev_month_days;
|
|
## strdays[i] = "#e0e0e0 " + to_string(day) + "#";
|
|
## }
|
|
## else if (i >= (month_days + start_of_month)) {
|
|
## day -= month_days;
|
|
## strdays[i] = "#e0e0e0 " + to_string(day) + "#";
|
|
## }
|
|
## else {
|
|
## strdays[i] = to_string(day);
|
|
## }
|
|
## pstrdays[++j] = strdays[i].c_str();
|
|
## //ESP_LOGI("bmx", "%s, i: %d, j: %d", pstrdays[j], i, j);
|
|
## i++;
|
|
## }
|
|
## pstrdays[++j] = newline;
|
|
## //ESP_LOGI("bmxnl", "%s, i: %d, j: %d", pstrdays[j], i, j);
|
|
## }
|
|
## pstrdays[j] = NULL; // terminator, overwrites last newline
|
|
## //ESP_LOGW("day", "terminating at: %d", j);
|
|
## lv_btnmatrix_set_btn_ctrl_all(bmx_calendar->obj, LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_RECOLOR);
|
|
## lv_btnmatrix_set_map(bmx_calendar->obj, pstrdays);
|
|
## lv_btnmatrix_set_btn_ctrl_all(bmx_calendar->obj, LV_BTNMATRIX_CTRL_CHECKABLE | LV_BTNMATRIX_CTRL_RECOLOR);
|
|
##
|
|
## - id: persist_calendar
|
|
## then:
|
|
## lambda: |-
|
|
## id(g_year_idx) = lv_dropdown_get_selected(cal_dd_year->obj);
|
|
## id(g_month_idx) = lv_dropdown_get_selected(cal_dd_month->obj);
|
|
## // copy year options to persistent globals
|
|
## const char* opts = lv_dropdown_get_options(cal_dd_year->obj);
|
|
## int opt_store_size = sizeof(id(g_options_year));
|
|
## strncpy(id(g_options_year), opts, opt_store_size);
|
|
## id(g_options_year)[opt_store_size] = '\0';
|
|
## //ESP_LOGI("year options", id(g_options_year));
|
|
##
|
|
## - id: get_calendar_days_state
|
|
## parameters:
|
|
## flag: std::string
|
|
## then:
|
|
## lambda: |-
|
|
## // count buttons
|
|
## int num_buttons = 0;
|
|
## auto* buttonmap = lv_btnmatrix_get_map(bmx_calendar->obj);
|
|
## int i = 0;
|
|
## for (; buttonmap[i] != NULL && buttonmap[i][0] != '\0' && i < 48; i++) {
|
|
## bool isNewLine = strcmp(buttonmap[i], "\n") == 0;
|
|
## if (!isNewLine) {
|
|
## num_buttons++;
|
|
## }
|
|
## }
|
|
## std::string sch_holidays = "";
|
|
## std::string pub_holidays = "";
|
|
## std::string vac_days = "";
|
|
## int h = 0;
|
|
## for(int i = 0; i < num_buttons; i++) {
|
|
## bool isSchoolHoliday = lv_btnmatrix_has_btn_ctrl(bmx_calendar->obj, i, LV_BTNMATRIX_CTRL_CHECKED);
|
|
## bool isPublicHoliday = false; //lv_btnmatrix_has_btn_ctrl(bmx_calendar->obj, i, LV_BTNMATRIX_CTRL_CUSTOM_1);
|
|
## bool isVacationDay = false; //lv_btnmatrix_has_btn_ctrl(bmx_calendar->obj, i, LV_BTNMATRIX_CTRL_CUSTOM_2);
|
|
## if(isSchoolHoliday || isPublicHoliday || isVacationDay) {
|
|
## sch_holidays = sch_holidays + lv_btnmatrix_get_btn_text(bmx_calendar->obj, i) + " ";
|
|
## h++;
|
|
## }
|
|
## }
|
|
## if(h > 0) {
|
|
## ESP_LOGI("day", "[%s] s: %s \tp: %s \tv: %s", flag.c_str(), sch_holidays.c_str(), pub_holidays.c_str(), vac_days.c_str());
|
|
## }
|
|
#- id: dump_can_message
|
|
# parameters:
|
|
# x: std::vector<uint8_t>&
|
|
# can_id: uint32_t
|
|
# remote_transmission_request: bool
|
|
# then:
|
|
# lambda: |-
|
|
# char buffer[80];
|
|
# char tag[16];
|
|
# // comment out following few lines if you don't want to deduplicate consecutive messages
|
|
# auto& y = id(can_lastframe);
|
|
# bool isduplicate = can_id == id(can_lastid);
|
|
# auto j = y.begin();
|
|
# if(x.size() == y.size()) {
|
|
# for(auto i = x.begin(); i != x.end() && isduplicate; ++i) {
|
|
# isduplicate = isduplicate && (*i == *j++);
|
|
# }
|
|
# }
|
|
# if(isduplicate) {
|
|
# return;
|
|
# }
|
|
# else {
|
|
# y.clear();
|
|
# y.insert(y.end(), x.begin(), x.end());
|
|
# id(can_lastid) = can_id;
|
|
# }
|
|
# // end of deduplication
|
|
# snprintf(tag, sizeof(tag), "CAN REC: 0x%X", can_id);
|
|
# snprintf(buffer, sizeof(buffer), " %d ", remote_transmission_request);
|
|
# std::string text = "";
|
|
# std::string line = buffer;
|
|
# std::string decoded = "";
|
|
# for(auto i = x.begin(); i != x.end(); ++i) {
|
|
# auto byte = *i;
|
|
# snprintf(buffer, sizeof(buffer), " %02X", byte);
|
|
# line += buffer;
|
|
# if(byte > 31 && byte < 127) {
|
|
# text += (char) byte;
|
|
# }
|
|
# else {
|
|
# text += ".";
|
|
# }
|
|
# }
|
|
# switch (can_id)
|
|
# {
|
|
# case ${CB_BATTERY_LIMITS}:
|
|
# {
|
|
# float battery_charge_voltage_limit = 0.1 * ((x[1] << 8) + x[0]); // unit = 0.1V
|
|
# float charge_current_limit = 0.1 * static_cast<int16_t>((x[3] << 8) + x[2]); // unit = 0.1A
|
|
# float discharge_current_limit = 0.1 * static_cast<int16_t>((x[5] << 8) + x[4]); // unit = 0.1A
|
|
# snprintf(buffer, sizeof(buffer), "BATTERY LIMITS: VMax= %.1fV IMaxChg= %.1fA IMaxDis= %.1fA", battery_charge_voltage_limit, charge_current_limit, discharge_current_limit);
|
|
# decoded += buffer;
|
|
# }
|
|
# break;
|
|
# case ${CB_BATTERY_STATE}:
|
|
# {
|
|
# uint soc = static_cast<uint16_t>((x[1] << 8) + x[0]);
|
|
# uint soh = static_cast<uint16_t>((x[3] << 8) + x[2]);
|
|
# snprintf(buffer, sizeof(buffer), "BATTERY STATE: SOC= %d%% SOH= %d%%", soc, soh);
|
|
# decoded += buffer;
|
|
# }
|
|
# break;
|
|
# case ${CB_BATTERY_STATUS}:
|
|
# {
|
|
# float system_voltage = 0.01 * static_cast<int16_t>((x[1] << 8) + x[0]); // unit = 0.01V Voltage of single module or average module voltage of system
|
|
# float system_current = 0.1 * static_cast<int16_t>((x[3] << 8) + x[2]); // unit = 0.1A Module or system total current
|
|
# float average_cell_temperature = 0.1 * static_cast<int16_t>((x[5] << 8) + x[4]); // unit = 0.1°C
|
|
# snprintf(buffer, sizeof(buffer), "BATTERY STATUS: VSYS= %.2fV ISYS= %.1fA TSYS= %.1f°C", system_voltage, system_current, average_cell_temperature);
|
|
# decoded += buffer;
|
|
# }
|
|
# break;
|
|
# case ${CB_BATTERY_FAULT}:
|
|
# {
|
|
# uint8_t protection1 = x[0];
|
|
# uint8_t protection2 = x[1];
|
|
# uint8_t alarm1 = x[2];
|
|
# uint8_t alarm2 = x[3];
|
|
# uint8_t module_numbers = x[4];
|
|
# char ch5 = x[5];
|
|
# char ch6 = x[6];
|
|
# bool discharge_over_current = protection1 & 0x80;
|
|
# bool cell_under_temperature = protection1 & 0x10;
|
|
# bool cell_over_temperature = protection1 & 0x08;
|
|
# bool cell_or_module_under_voltage = protection1 & 0x04;
|
|
# bool cell_or_module_over_voltage = protection1 & 0x02;
|
|
# bool system_error = protection2 & 0x8;
|
|
# bool charge_over_current = protection2 & 0x01;
|
|
# bool discharge_high_current = alarm1 & 0x80;
|
|
# bool cell_low_temperature = alarm1 & 0x10;
|
|
# bool cell_high_temperature = alarm1 & 0x08;
|
|
# bool cell_or_module_low_voltage = alarm1 & 0x04;
|
|
# bool cell_or_module_high_voltage = alarm1 & 0x02;
|
|
# bool internal_communication_fail = alarm2 & 0x8;
|
|
# bool charge_high_current = alarm2 & 0x01;
|
|
# snprintf(buffer, sizeof(buffer), "BATTERY PROTECT: %s%s%s%s%s%s%s ALARM= %s%s%s%s%s%s%s MN=%d %c%c", discharge_over_current ? "DOC " : "", cell_under_temperature ? "CUT " : "", cell_over_temperature ? "COT " : "", cell_or_module_under_voltage ? "CMUV " : "", cell_or_module_over_voltage ? "CMOV" : "", system_error ? "SERR " : "", charge_over_current ? "COC ": "", discharge_high_current ? "DHC " : "", cell_low_temperature ? "CLT " : "", cell_high_temperature ? "CHT " : "", cell_or_module_low_voltage ? "CMLV " : "", cell_or_module_high_voltage ? "CMHV" : "", internal_communication_fail ? "ICF " : "", charge_high_current ? "CHC ": "", module_numbers, ch5, ch6);
|
|
# decoded += buffer;
|
|
# }
|
|
# break;
|
|
# case ${CB_BATTERY_REQUEST_FLAG}:
|
|
# {
|
|
# uint8_t request_flag = x[0];
|
|
# bool charge_enable = request_flag & 0x80;
|
|
# bool discharge_enable = request_flag & 0x40;
|
|
# bool request_force_charge1 = request_flag & 0x20; // use bit 5, the SOC range is: 15~19%. Bit 4 is NULL. Bit 5 is designed for inverter allows battery to shut down, and able to wake battery up to charge it.
|
|
# bool request_force_charge2 = request_flag & 0x10; // Bit 5 the SOC range is 5~10%, Bit 4 the SOC range is 9~13%. Bit 4 is designed for inverter doesn`t want battery to shut down, able to charge battery before shut down to avoid low energy. We suggest inverter to use this bit, In this case, inverter itself should set a threshold of SOC: after force charge, only when battery SOC is higher than this threshold then inverter will allow discharge, to avoid force charge and discharge status change frequently.
|
|
# bool request_full_charge = request_flag & 0x08; // Reason: when battery is not full charged for long time, the accumulative error of SOC calculation will be too high and may not able to be charged or discharged as expected capacity. Logic: if SOC never higher than 97% in 30 days, will set this flag to 1. And when the SOC is 97%, the flag will be 0. How to: we suggest inverter to charge the battery by grid when this flag is 1.
|
|
# snprintf(buffer, sizeof(buffer), "BATTERY REQUEST: %s%s%s%s%s", charge_enable ? "CE " : "", discharge_enable ? "DE " : "", request_force_charge1 ? "RFORCECH1 " : "", request_force_charge2 ? "RFORCECH2 " : "", request_full_charge ? "RFULLCH" : "");
|
|
# decoded += buffer;
|
|
# }
|
|
# break;
|
|
# case ${CB_BATTERY_MANUFACTURER}:
|
|
# {
|
|
# std::string manufacturer(x.begin(), x.end());
|
|
# decoded += "BATTERY OEM: " + manufacturer;
|
|
# }
|
|
# break;
|
|
# }
|
|
# ESP_LOGI(tag, "%s %s %s", line.c_str(), text.c_str(), decoded.c_str()); |