Mogłem się w końcu pobawić donglem Epever - działa tak jak myślałem. Ponieważ chyba nigdzie nie ma gotowej konfiguracji dla HA, podzielę się swoją. Opis w instrukcji dongla jest niewiarygodnie zamotany, ale na szczęście można po prostu podłączyć się do jego AP (fabryczne hasło: 12345678), potem adres 10.10.100.254, login/hasło: admin. W sekcji STA wpisujemy dane swojej sieci WiFi 2.4GHz, w sekcji Other Setting zmieniamy protokół na serwer i port 9999 (portu 502 niestety nie przyjmuje), dobrze też zmienić domyślnego usera i hasło.
Konfigurację HA zrobiłem w 2 częściach: integracja modbus oraz sensory template trigger-based. Sensory modbus nie obsługują szablonów, a dane tu wymagają obróbki przed prezentacją; po drugie starałem się czytać rejestry blokami, bo tak jest efektywniej - i rozbijam to na sensory właśnie w sensorach template. Z modbusa do bezpośredniego używania jest tylko switch przełączający load, a reszta sensorów pełni rolę pomocniczą i równie dobrze można je ukryć.
Integracja modbus
modbus:
- name: 'Epever Tracer 2210AN'
type: rtuovertcp
host: 192.168.18.47
port: 9999
delay: 0
message_wait_milliseconds: 200
timeout: 5
switches:
# do włączania/wyłączania zasilania urządzeń podłączonych do kontrolera, gdy ustawienie/sensor
# 'Load controlling modes' = 0 (to oznacza właśnie manualną kontrolę). Ja używam tylko tego trybu,
# ale gdybym kiedyś chciał, to przy tych innych można wyłączać/wyłączać zasilanie za pomocą switcha (coil)
# na adresie 3. I wtedy działa to chyba tak, że przy włączonym load faktyczne włączenie zasilania zależy
# od ustawień trybu (np. harmonogram), a przy wyłączonym jest cały czas off.
- name: 'Manual load control'
unique_id: epever_manual_load_control
write_type: coil
address: 2
verify:
sensors:
- name: 'modbus data: epever, load controlling modes'
# 0x0000 Manual Control
# 0x0001 Light ON/OFF
# 0x0002 Light ON+ Timer/
# 0x0003 Time Control
unique_id: b9d49308-6533-4f33-8f05-dba8531e8793
input_type: holding
data_type: uint16
address: 0x903D
# data i czas na kontrolerze
- name: 'modbus data: epever, datetime'
unique_id: e2ece5da-5fe8-4044-8f9f-834b238361cf
input_type: holding
# 3 rejestry
count: 3
data_type: custom
structure: '>3H'
address: 0x9013
scan_interval: 60
# rzadko zmieniane ustawienia baterii (rodzaj, prądy ładowania, itd.)
- name: 'modbus data: epever, battery settings'
unique_id: a8a4d36d-b734-49eb-9fcd-b9b426184731
input_type: holding
# 15 rejestrów
count: 15
data_type: custom
structure: '>15H'
address: 0x9000
scan_interval: 0 # wyłączona aktualizacja, tylko przy starcie HA lub reload integracji
# status baterii i podłączonego sprzętu - tu są głównie informacje o błędach
- name: 'modbus data: epever, status'
unique_id: 4a3f9eb9-3120-4076-af19-b63c04bfe535
input_type: input
# 3 rejestry
count: 3
data_type: custom
structure: '>3H'
address: 0x3200
scan_interval: 60
# statystyki (napięcia min/max, ilość wytworzonego prądu, itd.), pierwsze 16 rejestrów
# wszystkich rejestrów jest 31, dla bezpieczeństwa dzielę je na pół, aby nie przekroczyć czasem 255 znaków
- name: 'modbus data: epever, statistics 1'
unique_id: a9544a0a-600a-4fbf-8e53-4a6205d46011
input_type: input
# 16 rejestrów
count: 16
data_type: custom
structure: '>16H'
address: 0x3300
scan_interval: 900 # 15 minut
# statystyki, kolejne 15 rejestrów
- name: 'modbus data: epever, statistics 2'
unique_id: a9544a0a-600a-4fbf-8e53-4a6205d46012
input_type: input
# 15 rejestrów
count: 15
data_type: custom
structure: '>15H'
address: 0x3310
scan_interval: 900 # 15 minut
# bieżące info o obciążeniu przez podłączone urządzenia
- name: 'modbus data: epever, load'
unique_id: 3e116ce2-a574-4d13-ae11-3bd8e2f862c6
input_type: input
count: 4
data_type: custom
structure: '>4H'
address: 0x310C
scan_interval: 60
# bieżące info o ładowaniu baterii; 21 rejestrów, małe liczby, ale nie są ciągłe adresy, więc na 2x
- name: 'modbus data: epever, charging 1'
unique_id: 967d0eaf-2019-4b9a-90dd-fd3c64784e9e
input_type: input
count: 19
data_type: custom
structure: '>19H'
address: 0x3100
scan_interval: 60
- name: 'modbus data: epever, charging 2'
unique_id: 278ed174-d21e-409d-b307-3a1b3610ae82
input_type: input
count: 2
data_type: custom
structure: '>2H'
address: 0x311A
scan_interval: 60
Właściwe sensory, integracja template
template:
- trigger:
- trigger: state
entity_id: sensor.modbus_data_epever_datetime
not_to: ['unknown','unavailable']
id: datetime
- trigger: state
entity_id: sensor.modbus_data_epever_battery_settings
not_to: ['unknown','unavailable']
id: batt_settings
- trigger: state
entity_id: sensor.modbus_data_epever_status
not_to: ['unknown','unavailable']
id: status
- trigger: state
entity_id: sensor.modbus_data_epever_statistics_1
not_to: ['unknown','unavailable']
id: statistics1
- trigger: state
entity_id: sensor.modbus_data_epever_statistics_2
not_to: ['unknown','unavailable']
id: statistics2
- trigger: state
entity_id: sensor.modbus_data_epever_load
not_to: ['unknown','unavailable']
id: load
- trigger: state
entity_id: sensor.modbus_data_epever_charging_1
not_to: ['unknown','unavailable']
id: charging1
- trigger: state
entity_id: sensor.modbus_data_epever_charging_2
not_to: ['unknown','unavailable']
id: charging2
- trigger: state
entity_id: sensor.modbus_data_epever_load_controlling_modes
not_to: ['unknown','unavailable']
id: load_control
action:
- variables:
# stałe
batt_type: '{{ { 0: "User defined", 1: "Sealed", 2: "GEL", 3: "Flooded" } if trigger.id == "batt_settings" }}'
battery_status_voltage: >-
{{ {
0: "Normal",
1: "Overvolt",
2: "Under volt",
3: "Low Volt Disconnect",
4: "Fault"
} if trigger.id == 'status' }}
battery_status_temperature: >-
{{ {
0: "Normal",
1: "Over Temperature",
2: "Low Temperature"
} if trigger.id == 'status' }}
battery_status_res: '{{ {0: "Normal", 1: "Abnormal" } if trigger.id == "status" }}'
battery_status_vol: '{{ {0: "Correct", 1: "Wrong" } if trigger.id == "status" }}'
charging_equipment_status_input_voltage: >-
{{ {
0: "Normal",
1: "No power connected",
2: "Higher Volt Input",
3: "Input Volt Error"
} if trigger.id == 'status' }}
charging_equipment_status_battery: >-
{{ {
0: "Not charging",
1: "Float",
2: "Boost",
3: "Equalization"
} if trigger.id == 'status' }}
fault_status: '{{ {0: "Normal", 1: "Fault" } if trigger.id == "status" }}'
running_status: '{{ {0: "Standby", 1: "Running" } if trigger.id == "status" }}'
discharging_equipment_status_voltage: >-
{{ {
0: "Normal",
1: "Low",
2: "High",
3: "No access input volt error"
} if trigger.id == 'status' }}
discharging_equipment_status_output: >-
{{ {
0: "Light Load",
1: "Moderate",
2: "Rated",
3: "Overload"
} if trigger.id == 'status' }}
load_controlling_mode: >-
{{ {
0: "Manual control",
1: "Light ON/OFF",
2: "Light ON + timer",
3: "Time control"
} if trigger.id == "load_control" }}
# zmienne (dane z modbus)
datetime: "{{ trigger.to_state.state.split(',')|map('int')|list if trigger.id == 'datetime' }}"
batt_settings: "{{ trigger.to_state.state.split(',')|map('int')|list if trigger.id == 'batt_settings' }}"
status: "{{ trigger.to_state.state.split(',')|map('int')|list if trigger.id == 'status' }}"
batt_status: >-
{{ {
'voltage': battery_status_voltage.get(status[0]|bitwise_and(0x0007)),
'temperature': battery_status_temperature.get((status[0]/2**4)|int|bitwise_and(0x000f)),
'internalResistance': battery_status_res.get((status[0]/2**8)|int|bitwise_and(0x0001)),
'ratedVoltage': battery_status_vol.get((status[0]/2**15)|int|bitwise_and(0x0001)),
} if trigger.id == 'status' }}
eq_status: >-
{{ {
'inputVoltage': charging_equipment_status_input_voltage.get((status[1]/2**14)|int|bitwise_and(0x0003)),
'mosfetShort': (status[1]/2**13)|int|bitwise_and(0x0001)|bool,
'chargingAntiReverseMosfetShort': (status[1]/2**12)|int|bitwise_and(0x0001)|bool,
'antiReverseMosfetShort': (status[1]/2**11)|int|bitwise_and(0x0001)|bool,
'inputOverCurrent': (status[1]/2**10)|int|bitwise_and(0x0001)|bool,
'loadOverCurrent': (status[1]/2**9)|int|bitwise_and(0x0001)|bool,
'loadShort': (status[1]/2**8)|int|bitwise_and(0x0001)|bool,
'loadMosfetShort': (status[1]/2**7)|int|bitwise_and(0x0001)|bool,
'pvInputShort': (status[1]/2**7)|int|bitwise_and(0x0001)|bool,
'battery': charging_equipment_status_battery.get((status[1]/2**2)|int|bitwise_and(0x0003)),
'fault': (status[1]/2)|int|bitwise_and(0x0001)|bool,
'running': status[1]|int|bitwise_and(0x0001)|bool,
} if trigger.id == 'status' }}
dis_status: >-
{{ {
'inputVoltage': discharging_equipment_status_voltage.get((status[2]/2**14)|int|bitwise_and(0x0003)),
'outputPower': discharging_equipment_status_voltage.get((status[2]/2**12)|int|bitwise_and(0x0003)),
'shortCircuit': (status[2]/2**11)|int|bitwise_and(0x0001)|bool,
'unableDischarge': (status[2]/2**10)|int|bitwise_and(0x0001)|bool,
'unableStopDischarging': (status[2]/2**9)|int|bitwise_and(0x0001)|bool,
'outputVoltageAbnormal': (status[2]/2**8)|int|bitwise_and(0x0001)|bool,
'inputOverpressure': (status[2]/2**7)|int|bitwise_and(0x0001)|bool,
'highVoltageSideShortCircuit': (status[2]/2**6)|int|bitwise_and(0x0001)|bool,
'boostOverpressure': (status[2]/2**5)|int|bitwise_and(0x0001)|bool,
'outputOverpressure': (status[2]/2**4)|int|bitwise_and(0x0001)|bool,
'fault': (status[2]/2)|int|bitwise_and(0x0001)|bool,
'running': status[2]|int|bitwise_and(0x0001)|bool,
} if trigger.id == 'status' }}
statistics1: >-
{% if trigger.id == 'statistics1' %}
{% set s = trigger.to_state.state.split(',')|map('float')|list %}
{{ {
'maxVoltToday': (s[0]/100)|round(1),
'minVoltToday': (s[1]/100)|round(1),
'maxBatteryVoltToday': (s[2]/100)|round(1),
'minBatteryVoltToday': (s[3]/100)|round(1),
'consumedEnergyToday': ((s[4] + s[5]*16)/100)|round(0),
'consumedEnergyMonth': ((s[6] + s[7]*16)/100)|round(1),
'consumedEnergyYear': ((s[8] + s[9]*16)/100)|round(1),
'totalConsumedEnergy': ((s[10] + s[11]*16)/100)|round(1),
'generatedEnergyToday': ((s[12] + s[13]*16)/100)|round(0),
'generatedEnergyMonth': ((s[14] + s[15]*16)/100)|round(1),
} }}
{% endif %}
statistics2: >-
{% if trigger.id == 'statistics2' %}
{% set s = trigger.to_state.state.split(',')|map('float')|list %}
{% set s11 = 0 if s[11] == 0xFFFF else s[11] %}
{% set s12 = 0 if s[12] == 0xFFFF else s[12] %}
{{ {
'generatedEnergyYear': ((s[0] + s[1]*16)/100)|round(1),
'totalGeneratedEnergy': ((s[2] + s[3]*16)/100)|round(1),
'carbonDioxideReduction': ((s[4] + s[5]*16)/100)|round(1),
'batteryVoltage': (s[10]/100)|round(1),
'batteryCurrent': ((s11 + s12*16)/100)|round(1),
'batteryTemperature': (s[13]/100)|round(1),
'ambientTemperature': (s[14]/100)|round(1),
} }}
{% endif %}
load: >-
{% if trigger.id == 'load' %}
{% set s = trigger.to_state.state.split(',')|map('int')|list %}
{{ {
'loadVoltage': (s[0]/100)|round(1),
'loadCurrent': (s[1]/100)|round(1),
'loadPower': ((s[2] + s[3]*16)/100)|round(1),
} }}
{% endif %}
charging1: >-
{% if trigger.id == 'charging1' %}
{% set s = trigger.to_state.state.split(',')|map('int')|list %}
{{ {
'chargingInputVoltage': (s[0]/100)|round(1),
'chargingInputCurrent': (s[1]/100)|round(1),
'chargingInputPower': ((s[2] + s[3]*16)/100)|round(1),
'chargingOutputVoltage': (s[4]/100)|round(1),
'chargingOutputCurrent': (s[5]/100)|round(1),
'chargingOutputPower': ((s[6] + s[7]*16)/100)|round(1),
'dischargingOutputVoltage': (s[12]/100)|round(1),
'dischargingOutputCurrent': (s[13]/100)|round(1),
'dischargingOutputPower': ((s[14] + s[15]*16)/100)|round(1),
'batteryTemperature': (s[16]/100)|round(1),
'temperatureInside': (s[17]/100)|round(1),
'powerComponentsTemperature': (s[18]/100)|round(1),
} }}
{% endif %}
charging2: >-
{% if trigger.id == 'charging2' %}
{% set s = trigger.to_state.state.split(',')|map('int')|list %}
{{ {
'batterySoC': s[0]|round(0),
'remoteBatteryTemperature': (s[1]/100)|round(1),
} }}
{% endif %}
load_control: "{{ load_controlling_mode.get(trigger.to_state.state|int(0)) if trigger.id == 'load_control' }}"
sensor:
- name: "Epever, date and time"
unique_id: 40a34179-2d3f-4f6d-9575-9d9e3848d939
state: >-
{% if trigger.id == 'datetime' %}
{% set year = (2000 + datetime[2]/256)|int %}
{% set month = datetime[2]|bitwise_and(0xff) %}
{% set day = (datetime[1]/256)|int %}
{% set hour = datetime[1]|bitwise_and(0xff) %}
{% set min = (datetime[0]/256)|int %}
{% set sec = datetime[0]|bitwise_and(0xff) %}
{{ '{}-{:02}-{:02} {:02}:{:02}:{:02}'.format(year,month,day,hour,min,sec) }}
{% else %}
{{ this.state|default('unknown') }}
{% endif %}
- name: "Epever, battery settings"
unique_id: 72766f7d-b80b-4b3b-a614-898c11dac4ea
state: >-
{{ batt_type.get(batt_settings[0]) if trigger.id == 'batt_settings' else this.state|default('unknown') }}
attributes:
batteryType: "{{ batt_type.get(batt_settings[0]) if trigger.id == 'batt_settings' else this.attributes.get('batteryType') }}"
batteryCapacity: "{{ batt_settings[1] if trigger.id == 'batt_settings' else this.attributes.get('batteryCapacity') }}"
temperatureCompensationCoefficient: "{{ batt_settings[2]/100 if trigger.id == 'batt_settings' else this.attributes.get('temperatureCompensationCoefficient') }}"
highVoltDisconnect: "{{ batt_settings[3]/100 if trigger.id == 'batt_settings' else this.attributes.get('highVoltDisconnect') }}"
chargingLimitVoltage: "{{ batt_settings[4]/100 if trigger.id == 'batt_settings' else this.attributes.get('chargingLimitVoltage') }}"
overVoltageReconnect: "{{ batt_settings[5]/100 if trigger.id == 'batt_settings' else this.attributes.get('overVoltageReconnect') }}"
equalizationVoltage: "{{ batt_settings[6]/100 if trigger.id == 'batt_settings' else this.attributes.get('equalizationVoltage') }}"
boostVoltage: "{{ batt_settings[7]/100 if trigger.id == 'batt_settings' else this.attributes.get('boostVoltage') }}"
floatVoltage: "{{ batt_settings[8]/100 if trigger.id == 'batt_settings' else this.attributes.get('floatVoltage') }}"
boostReconnectVoltage: "{{ batt_settings[9]/100 if trigger.id == 'batt_settings' else this.attributes.get('boostReconnectVoltage') }}"
lowVoltageReconnect: "{{ batt_settings[10]/100 if trigger.id == 'batt_settings' else this.attributes.get('lowVoltageReconnect') }}"
underVoltageRecover: "{{ batt_settings[11]/100 if trigger.id == 'batt_settings' else this.attributes.get('underVoltageRecover') }}"
underVoltageWarning: "{{ batt_settings[12]/100 if trigger.id == 'batt_settings' else this.attributes.get('underVoltageWarning') }}"
lowVoltageDisconnect: "{{ batt_settings[13]/100 if trigger.id == 'batt_settings' else this.attributes.get('lowVoltageDisconnect') }}"
dischargingLimitVoltage: "{{ batt_settings[14]/100 if trigger.id == 'batt_settings' else this.attributes.get('dischargingLimitVoltage') }}"
- name: "Epever, battery status"
unique_id: de0d3703-12af-40b2-80d3-54d7ac51b4e6
state: "{{ batt_status.items()|map(attribute='1')|join(', ') if trigger.id == 'status' else this.state|default('unknown') }}"
attributes:
voltage: "{{ batt_status['voltage'] if trigger.id == 'status' else this.attributes.get('voltage') }}"
temperature: "{{ batt_status['temperature'] if trigger.id == 'status' else this.attributes.get('temperature') }}"
internalResistance: "{{ batt_status['internalResistance'] if trigger.id == 'status' else this.attributes.get('internalResistance') }}"
ratedVoltage: "{{ batt_status['ratedVoltage'] if trigger.id == 'status' else this.attributes.get('ratedVoltage') }}"
- name: "Epever, equipment status"
unique_id: 9e9d7117-4af1-44cc-bcf1-d15d63e4b982
state: >-
{% if trigger.id == 'status' %}
{% set inputVoltage = eq_status['inputVoltage'] %}
{% set battery = eq_status['battery'] %}
{% set running = 'Running' if eq_status['running'] else 'Not running' %}
{% set problem = eq_status.items()|selectattr('1','eq',true)|rejectattr('0','eq','running')|first is defined %}
{{ inputVoltage }}, {{ battery }}, {{ running }}, {{ 'Problem!' if problem else 'OK' }}
{% else %}
{{ this.state|default('unknown') }}
{% endif %}
attributes:
inputVoltage: "{{ eq_status['inputVoltage'] if trigger.id == 'status' else this.attributes.get('inputVoltage') }}"
mosfetShort: "{{ eq_status['mosfetShort'] if trigger.id == 'status' else this.attributes.get('mosfetShort') }}"
chargingAntiReverseMosfetShort: "{{ eq_status['chargingAntiReverseMosfetShort'] if trigger.id == 'status' else this.attributes.get('chargingAntiReverseMosfetShort') }}"
antiReverseMosfetShort: "{{ eq_status['antiReverseMosfetShort'] if trigger.id == 'status' else this.attributes.get('antiReverseMosfetShort') }}"
inputOverCurrent: "{{ eq_status['inputOverCurrent'] if trigger.id == 'status' else this.attributes.get('inputOverCurrent') }}"
loadOverCurrent: "{{ eq_status['loadOverCurrent'] if trigger.id == 'status' else this.attributes.get('loadOverCurrent') }}"
loadShort: "{{ eq_status['loadShort'] if trigger.id == 'status' else this.attributes.get('loadShort') }}"
loadMosfetShort: "{{ eq_status['loadMosfetShort'] if trigger.id == 'status' else this.attributes.get('loadMosfetShort') }}"
pvInputShort: "{{ eq_status['pvInputShort'] if trigger.id == 'status' else this.attributes.get('pvInputShort') }}"
battery: "{{ eq_status['battery'] if trigger.id == 'status' else this.attributes.get('battery') }}"
fault: "{{ eq_status['fault'] if trigger.id == 'status' else this.attributes.get('fault') }}"
running: "{{ eq_status['running'] if trigger.id == 'status' else this.attributes.get('running') }}"
- name: "Epever, discharge status"
unique_id: 89392181-bf34-43bd-ba8e-eccbe00460b5
state: >-
{% if trigger.id == 'status' %}
{% set inputVoltage = dis_status['inputVoltage'] %}
{% set outputPower = dis_status['outputPower'] %}
{% set running = 'Running' if dis_status['running'] else 'Not running' %}
{% set problem = dis_status.items()|selectattr('1','eq',true)|rejectattr('0','eq','running')|first is defined %}
{{ inputVoltage }}, {{ outputPower }}, {{ running }}, {{ 'Problem!' if problem else 'OK' }}
{% else %}
{{ this.state|default('unknown') }}
{% endif %}
attributes:
inputVoltage: "{{ dis_status['inputVoltage'] if trigger.id == 'status' else this.attributes.get('inputVoltage') }}"
outputPower: "{{ dis_status['outputPower'] if trigger.id == 'status' else this.attributes.get('outputPower') }}"
shortCircuit: "{{ dis_status['shortCircuit'] if trigger.id == 'status' else this.attributes.get('shortCircuit') }}"
unableDischarge: "{{ dis_status['unableDischarge'] if trigger.id == 'status' else this.attributes.get('unableDischarge') }}"
unableStopDischarging: "{{ dis_status['unableStopDischarging'] if trigger.id == 'status' else this.attributes.get('unableStopDischarging') }}"
outputVoltageAbnormal: "{{ dis_status['outputVoltageAbnormal'] if trigger.id == 'status' else this.attributes.get('outputVoltageAbnormal') }}"
inputOverpressure: "{{ dis_status['inputOverpressure'] if trigger.id == 'status' else this.attributes.get('inputOverpressure') }}"
highVoltageSideShortCircuit: "{{ dis_status['highVoltageSideShortCircuit'] if trigger.id == 'status' else this.attributes.get('highVoltageSideShortCircuit') }}"
boostOverpressure: "{{ dis_status['boostOverpressure'] if trigger.id == 'status' else this.attributes.get('boostOverpressure') }}"
outputOverpressure: "{{ dis_status['outputOverpressure'] if trigger.id == 'status' else this.attributes.get('outputOverpressure') }}"
fault: "{{ dis_status['fault'] if trigger.id == 'status' else this.attributes.get('fault') }}"
running: "{{ dis_status['running'] if trigger.id == 'status' else this.attributes.get('running') }}"
- name: "Epever, statistics"
unique_id: 638e4bee-80e9-4f9d-a44b-2244ab8f2858
state: "{{ statistics1['generatedEnergyToday'] if trigger.id == 'statistics1' else this.state|default(0) }}"
device_class: "energy"
unit_of_measurement: "Wh"
attributes:
maxVoltToday: "{{ statistics1['maxVoltToday'] if trigger.id == 'statistics1' else this.attributes.get('maxVoltToday') }}"
minVoltToday: "{{ statistics1['minVoltToday'] if trigger.id == 'statistics1' else this.attributes.get('minVoltToday') }}"
maxBatteryVoltToday: "{{ statistics1['maxBatteryVoltToday'] if trigger.id == 'statistics1' else this.attributes.get('maxBatteryVoltToday') }}"
minBatteryVoltToday: "{{ statistics1['minBatteryVoltToday'] if trigger.id == 'statistics1' else this.attributes.get('minBatteryVoltToday') }}"
consumedEnergyToday_Wh: "{{ statistics1['consumedEnergyToday'] if trigger.id == 'statistics1' else this.attributes.get('consumedEnergyToday_Wh') }}"
consumedEnergyMonth: "{{ statistics1['consumedEnergyMonth'] if trigger.id == 'statistics1' else this.attributes.get('consumedEnergyMonth') }}"
consumedEnergyYear: "{{ statistics1['consumedEnergyYear'] if trigger.id == 'statistics1' else this.attributes.get('consumedEnergyYear') }}"
totalConsumedEnergy: "{{ statistics1['totalConsumedEnergy'] if trigger.id == 'statistics1' else this.attributes.get('totalConsumedEnergy') }}"
generatedEnergyToday_Wh: "{{ statistics1['generatedEnergyToday'] if trigger.id == 'statistics1' else this.attributes.get('generatedEnergyToday_Wh') }}"
generatedEnergyMonth: "{{ statistics1['generatedEnergyMonth'] if trigger.id == 'statistics1' else this.attributes.get('generatedEnergyMonth') }}"
generatedEnergyYear: "{{ statistics2['generatedEnergyYear'] if trigger.id == 'statistics2' else this.attributes.get('generatedEnergyYear') }}"
totalGeneratedEnergy: "{{ statistics2['totalGeneratedEnergy'] if trigger.id == 'statistics2' else this.attributes.get('totalGeneratedEnergy') }}"
carbonDioxideReduction: "{{ statistics2['carbonDioxideReduction'] if trigger.id == 'statistics2' else this.attributes.get('carbonDioxideReduction') }}"
batteryVoltage: "{{ statistics2['batteryVoltage'] if trigger.id == 'statistics2' else this.attributes.get('batteryVoltage') }}"
batteryCurrent: "{{ statistics2['batteryCurrent'] if trigger.id == 'statistics2' else this.attributes.get('batteryCurrent') }}"
batteryTemperature: "{{ statistics2['batteryTemperature'] if trigger.id == 'statistics2' else this.attributes.get('batteryTemperature') }}"
ambientTemperature: "{{ statistics2['ambientTemperature'] if trigger.id == 'statistics2' else this.attributes.get('ambientTemperature') }}"
- name: "Epever, load"
unique_id: 8b951010-2174-4b3d-bf8e-a4cdf1ccbdb3
state: "{{ load['loadVoltage'] if trigger.id == 'load' else this.state|default(0) }}"
unit_of_measurement: "V"
attributes:
loadVoltage: "{{ load['loadVoltage'] if trigger.id == 'load' else this.attributes.get('loadVoltage') }}"
loadCurrent: "{{ load['loadCurrent'] if trigger.id == 'load' else this.attributes.get('loadCurrent') }}"
loadPower: "{{ load['loadPower'] if trigger.id == 'load' else this.attributes.get('loadPower') }}"
- name: "Epever, charging"
unique_id: 8eb904bd-b30d-4624-b719-c03a9e8f0023
state: "{{ charging1['chargingOutputVoltage'] if trigger.id == 'charging1' else this.state|default(0) }}"
unit_of_measurement: "V"
attributes:
chargingInputVoltage: "{{ charging1['chargingInputVoltage'] if trigger.id == 'charging1' else this.attributes.get('chargingInputVoltage') }}"
chargingInputCurrent: "{{ charging1['chargingInputCurrent'] if trigger.id == 'charging1' else this.attributes.get('chargingInputCurrent') }}"
chargingInputPower: "{{ charging1['chargingInputPower'] if trigger.id == 'charging1' else this.attributes.get('chargingInputPower') }}"
chargingOutputVoltage: "{{ charging1['chargingOutputVoltage'] if trigger.id == 'charging1' else this.attributes.get('chargingOutputVoltage') }}"
chargingOutputCurrent: "{{ charging1['chargingOutputCurrent'] if trigger.id == 'charging1' else this.attributes.get('chargingOutputCurrent') }}"
chargingOutputPower: "{{ charging1['chargingOutputPower'] if trigger.id == 'charging1' else this.attributes.get('chargingOutputPower') }}"
dischargingOutputVoltage: "{{ charging1['dischargingOutputVoltage'] if trigger.id == 'charging1' else this.attributes.get('dischargingOutputVoltage') }}"
dischargingOutputCurrent: "{{ charging1['dischargingOutputCurrent'] if trigger.id == 'charging1' else this.attributes.get('dischargingOutputCurrent') }}"
dischargingOutputPower: "{{ charging1['dischargingOutputPower'] if trigger.id == 'charging1' else this.attributes.get('dischargingOutputPower') }}"
batteryTemperature: "{{ charging1['batteryTemperature'] if trigger.id == 'charging1' else this.attributes.get('batteryTemperature') }}"
temperatureInside: "{{ charging1['temperatureInside'] if trigger.id == 'charging1' else this.attributes.get('temperatureInside') }}"
powerComponentsTemperature: "{{ charging1['powerComponentsTemperature'] if trigger.id == 'charging1' else this.attributes.get('powerComponentsTemperature') }}"
batterySoC: "{{ charging2['batterySoC'] if trigger.id == 'charging2' else this.attributes.get('batterySoC') }}"
remoteBatteryTemperature: "{{ charging2['remoteBatteryTemperature'] if trigger.id == 'charging2' else this.attributes.get('remoteBatteryTemperature') }}"
- name: "Epever, load control"
unique_id: 3739731e-a961-4e17-8115-f7fa5fc9e93a
state: "{{ load_control if trigger.id == 'load_control' else this.state|default('unknown') }}"
Skrypt do synchronizacji daty i czasu na kontrolerze
sequence:
- action: modbus.write_register
data:
hub: Epever Tracer 2210AN
address: 36883
value: >-
{% set n = now() %}
{% set d2 = (n.year - 2000)*256 + n.month %}
{% set d1 = n.day*256 + n.hour %}
{% set d0 = n.minute*256 + n.second %}
{{ [d0,d1,d2] }}
alias: Epever, sync datetime
Rozbujałem się i wyszło tego całkiem dużo
, kilka przykładów:
Obrazki
Edycja & ostrzeżenie: po kilku dniach, wbudowany serwer portu szeregowego przestał odpowiadać. Restart, odłączenie zasilania oraz reset do ustawień fabrycznych + ponowna konfiguracja nie pomogły. Adapter nie pokazuje logów, więc diabli wiedzą co mu dolega.
Każdy sprzęt może się popsuć, natomiast z tym donglem jest jeszcze 1 poważny problem: po podłączeniu do WiFi wciąż aktywny jest AP i nie da się go wyłączyć, ani zmienić mu hasła. Zaś strona www pokazuje hasła otwartym tekstem. Więc jedyna linia obrony przed ogłaszaniem wszem i wobec hasła do naszego WiFi, to użytkownik/hasło web portalu, z maksymalną długością 15 znaków.
Reasumując, jednak nie polecam!