Skip to content

Commit ef22620

Browse files
authored
Merge pull request #183 from reserve85/dev
add some improvements
2 parents 5b22622 + fe441e1 commit ef22620

5 files changed

Lines changed: 128 additions & 28 deletions

File tree

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## V1.91
4+
### script
5+
* support Home Assistant over HTTPS (https://github.com/reserve85/HoymilesZeroExport/issues/178)
6+
* Support login credentials for Tasmota (https://github.com/reserve85/HoymilesZeroExport/issues/159)
7+
* update.sh supports custom branch, for example to update to dev path. usage: ./update.sh dev
8+
* option to disable a inverter (@tester277)
9+
* option to specify a specific emeter-index for ShellyEM [possible values: 0...1]. (https://github.com/reserve85/HoymilesZeroExport/issues/181)
10+
### config
11+
* add `[HOMEASSISTANT]`: `HA_HTTPS`
12+
* add `[INTERMEDIATE_HOMEASSISTANT]`: `HA_HTTPS_INTERMEDIATE`
13+
* add `[TASMOTA]`: `USER` and `PASS`
14+
* add `[TASMOTA_INTERMEDIATE]`: `USER_INTERMEDIATE` and `PASS_INTERMEDIATE`
15+
* add `[INVERTER_x]`: `ENABLED`
16+
* add `[SHELLY]`: `EMETER_INDEX`
17+
* add `[INTERMEDIATE_SHELLY]`: `EMETER_INDEX`
18+
319
## V1.90
420
### script
521
* fix HOY_BATTERY_THRESHOLD_NORMAL_LIMIT_IN_V, see https://github.com/reserve85/HoymilesZeroExport/issues/174

HoymilesZeroExport.py

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1616

1717
__author__ = "Tobias Kraft"
18-
__version__ = "1.90"
18+
__version__ = "1.91"
1919

2020
import requests
2121
import time
@@ -339,7 +339,7 @@ def GetHoymilesAvailable():
339339
for i in range(INVERTER_COUNT):
340340
try:
341341
WasAvail = AVAILABLE[i]
342-
AVAILABLE[i] = DTU.GetAvailable(i)
342+
AVAILABLE[i] = ENABLED[i] and DTU.GetAvailable(i)
343343
if AVAILABLE[i]:
344344
GetHoymilesAvailable = True
345345
if not WasAvail:
@@ -628,21 +628,26 @@ def GetPowermeterWatts(self) -> int:
628628
raise NotImplementedError()
629629

630630
class Tasmota(Powermeter):
631-
def __init__(self, ip: str, json_status: str, json_payload_mqtt_prefix: str, json_power_mqtt_label: str, json_power_input_mqtt_label: str, json_power_output_mqtt_label: str, json_power_calculate: bool):
631+
def __init__(self, ip: str, user: str, password: str, json_status: str, json_payload_mqtt_prefix: str, json_power_mqtt_label: str, json_power_input_mqtt_label: str, json_power_output_mqtt_label: str, json_power_calculate: bool):
632632
self.ip = ip
633+
self.user = user
634+
self.password = password
633635
self.json_status = json_status
634636
self.json_payload_mqtt_prefix = json_payload_mqtt_prefix
635637
self.json_power_mqtt_label = json_power_mqtt_label
636638
self.json_power_input_mqtt_label = json_power_input_mqtt_label
637639
self.json_power_output_mqtt_label = json_power_output_mqtt_label
638640
self.json_power_calculate = json_power_calculate
639641

640-
def GetJson(self, path):
642+
def GetJson(self, path):
641643
url = f'http://{self.ip}{path}'
642644
return session.get(url, timeout=10).json()
643645

644646
def GetPowermeterWatts(self):
645-
ParsedData = self.GetJson('/cm?cmnd=status%2010')
647+
if not self.user:
648+
ParsedData = self.GetJson('/cm?cmnd=status%2010')
649+
else:
650+
ParsedData = self.GetJson(f'/cm?user={self.user}&password={self.password}&cmnd=status%2010')
646651
if not self.json_power_calculate:
647652
return CastToInt(ParsedData[self.json_status][self.json_payload_mqtt_prefix][self.json_power_mqtt_label])
648653
else:
@@ -651,10 +656,11 @@ def GetPowermeterWatts(self):
651656
return CastToInt(input - ouput)
652657

653658
class Shelly(Powermeter):
654-
def __init__(self, ip: str, user: str, password: str):
659+
def __init__(self, ip: str, user: str, password: str, emeterindex: str):
655660
self.ip = ip
656661
self.user = user
657662
self.password = password
663+
self.emeterindex = emeterindex
658664

659665
def GetJson(self, path):
660666
url = f'http://{self.ip}{path}'
@@ -679,7 +685,10 @@ def GetPowermeterWatts(self):
679685

680686
class ShellyEM(Shelly):
681687
def GetPowermeterWatts(self):
682-
return sum(CastToInt(emeter['power']) for emeter in self.GetJson('/status')['emeters'])
688+
if self.emeterindex:
689+
return CastToInt(self.GetJson(f'/emeter/{self.emeterindex}')['power'])
690+
else:
691+
return sum(CastToInt(emeter['power']) for emeter in self.GetJson('/status')['emeters'])
683692

684693
class Shelly3EM(Shelly):
685694
def GetPowermeterWatts(self):
@@ -766,17 +775,21 @@ def GetPowermeterWatts(self):
766775
return CastToInt(input - output)
767776

768777
class HomeAssistant(Powermeter):
769-
def __init__(self, ip: str, port: str, access_token: str, current_power_entity: str, power_calculate: bool, power_input_alias: str, power_output_alias: str):
778+
def __init__(self, ip: str, port: str, use_https: bool, access_token: str, current_power_entity: str, power_calculate: bool, power_input_alias: str, power_output_alias: str):
770779
self.ip = ip
771780
self.port = port
781+
self.use_https = use_https
772782
self.access_token = access_token
773783
self.current_power_entity = current_power_entity
774784
self.power_calculate = power_calculate
775785
self.power_input_alias = power_input_alias
776786
self.power_output_alias = power_output_alias
777787

778788
def GetJson(self, path):
779-
url = f"http://{self.ip}:{self.port}{path}"
789+
if self.use_https:
790+
url = f"https://{self.ip}:{self.port}{path}"
791+
else:
792+
url = f"http://{self.ip}:{self.port}{path}"
780793
headers = {"Authorization": "Bearer " + self.access_token, "content-type": "application/json"}
781794
return session.get(url, headers=headers, timeout=10).json()
782795

@@ -1110,15 +1123,18 @@ def CreatePowermeter() -> Powermeter:
11101123
shelly_ip = config.get('SHELLY', 'SHELLY_IP')
11111124
shelly_user = config.get('SHELLY', 'SHELLY_USER')
11121125
shelly_pass = config.get('SHELLY', 'SHELLY_PASS')
1126+
shelly_emeterindex = config.get('SHELLY', 'EMETER_INDEX')
11131127
if config.getboolean('SELECT_POWERMETER', 'USE_SHELLY_EM'):
1114-
return ShellyEM(shelly_ip, shelly_user, shelly_pass)
1128+
return ShellyEM(shelly_ip, shelly_user, shelly_pass, shelly_emeterindex)
11151129
elif config.getboolean('SELECT_POWERMETER', 'USE_SHELLY_3EM'):
1116-
return Shelly3EM(shelly_ip, shelly_user, shelly_pass)
1130+
return Shelly3EM(shelly_ip, shelly_user, shelly_pass, shelly_emeterindex)
11171131
elif config.getboolean('SELECT_POWERMETER', 'USE_SHELLY_3EM_PRO'):
1118-
return Shelly3EMPro(shelly_ip, shelly_user, shelly_pass)
1132+
return Shelly3EMPro(shelly_ip, shelly_user, shelly_pass, shelly_emeterindex)
11191133
elif config.getboolean('SELECT_POWERMETER', 'USE_TASMOTA'):
11201134
return Tasmota(
11211135
config.get('TASMOTA', 'TASMOTA_IP'),
1136+
config.get('TASMOTA', 'TASMOTA_USER'),
1137+
config.get('TASMOTA', 'TASMOTA_PASS'),
11221138
config.get('TASMOTA', 'TASMOTA_JSON_STATUS'),
11231139
config.get('TASMOTA', 'TASMOTA_JSON_PAYLOAD_MQTT_PREFIX'),
11241140
config.get('TASMOTA', 'TASMOTA_JSON_POWER_MQTT_LABEL'),
@@ -1151,6 +1167,7 @@ def CreatePowermeter() -> Powermeter:
11511167
return HomeAssistant(
11521168
config.get('HOMEASSISTANT', 'HA_IP'),
11531169
config.get('HOMEASSISTANT', 'HA_PORT'),
1170+
config.getboolean('HOMEASSISTANT', 'HA_HTTPS', fallback=False),
11541171
config.get('HOMEASSISTANT', 'HA_ACCESSTOKEN'),
11551172
config.get('HOMEASSISTANT', 'HA_CURRENT_POWER_ENTITY'),
11561173
config.getboolean('HOMEASSISTANT', 'HA_POWER_CALCULATE'),
@@ -1177,9 +1194,12 @@ def CreateIntermediatePowermeter(dtu: DTU) -> Powermeter:
11771194
shelly_ip = config.get('INTERMEDIATE_SHELLY', 'SHELLY_IP_INTERMEDIATE')
11781195
shelly_user = config.get('INTERMEDIATE_SHELLY', 'SHELLY_USER_INTERMEDIATE')
11791196
shelly_pass = config.get('INTERMEDIATE_SHELLY', 'SHELLY_PASS_INTERMEDIATE')
1197+
shelly_emeterindex = config.get('INTERMEDIATE_SHELLY', 'EMETER_INDEX')
11801198
if config.getboolean('SELECT_INTERMEDIATE_METER', 'USE_TASMOTA_INTERMEDIATE'):
11811199
return Tasmota(
11821200
config.get('INTERMEDIATE_TASMOTA', 'TASMOTA_IP_INTERMEDIATE'),
1201+
config.get('INTERMEDIATE_TASMOTA', 'TASMOTA_USER_INTERMEDIATE'),
1202+
config.get('INTERMEDIATE_TASMOTA', 'TASMOTA_PASS_INTERMEDIATE'),
11831203
config.get('INTERMEDIATE_TASMOTA', 'TASMOTA_JSON_STATUS_INTERMEDIATE'),
11841204
config.get('INTERMEDIATE_TASMOTA', 'TASMOTA_JSON_PAYLOAD_MQTT_PREFIX_INTERMEDIATE'),
11851205
config.get('INTERMEDIATE_TASMOTA', 'TASMOTA_JSON_POWER_MQTT_LABEL_INTERMEDIATE'),
@@ -1188,15 +1208,15 @@ def CreateIntermediatePowermeter(dtu: DTU) -> Powermeter:
11881208
config.getboolean('INTERMEDIATE_TASMOTA', 'TASMOTA_JSON_POWER_CALCULATE_INTERMEDIATE', fallback=False)
11891209
)
11901210
elif config.getboolean('SELECT_INTERMEDIATE_METER', 'USE_SHELLY_EM_INTERMEDIATE'):
1191-
return ShellyEM(shelly_ip, shelly_user, shelly_pass)
1211+
return ShellyEM(shelly_ip, shelly_user, shelly_pass, shelly_emeterindex)
11921212
elif config.getboolean('SELECT_INTERMEDIATE_METER', 'USE_SHELLY_3EM_INTERMEDIATE'):
1193-
return Shelly3EM(shelly_ip, shelly_user, shelly_pass)
1213+
return Shelly3EM(shelly_ip, shelly_user, shelly_pass, shelly_emeterindex)
11941214
elif config.getboolean('SELECT_INTERMEDIATE_METER', 'USE_SHELLY_3EM_PRO_INTERMEDIATE'):
1195-
return Shelly3EMPro(shelly_ip, shelly_user, shelly_pass)
1215+
return Shelly3EMPro(shelly_ip, shelly_user, shelly_pass, shelly_emeterindex)
11961216
elif config.getboolean('SELECT_INTERMEDIATE_METER', 'USE_SHELLY_1PM_INTERMEDIATE'):
1197-
return Shelly1PM(shelly_ip, shelly_user, shelly_pass)
1217+
return Shelly1PM(shelly_ip, shelly_user, shelly_pass, shelly_emeterindex)
11981218
elif config.getboolean('SELECT_INTERMEDIATE_METER', 'USE_SHELLY_PLUS_1PM_INTERMEDIATE'):
1199-
return ShellyPlus1PM(shelly_ip, shelly_user, shelly_pass)
1219+
return ShellyPlus1PM(shelly_ip, shelly_user, shelly_pass, shelly_emeterindex)
12001220
elif config.getboolean('SELECT_INTERMEDIATE_METER', 'USE_ESPHOME_INTERMEDIATE'):
12011221
return ESPHome(
12021222
config.get('INTERMEDIATE_ESPHOME', 'ESPHOME_IP_INTERMEDIATE'),
@@ -1229,6 +1249,7 @@ def CreateIntermediatePowermeter(dtu: DTU) -> Powermeter:
12291249
return HomeAssistant(
12301250
config.get('INTERMEDIATE_HOMEASSISTANT', 'HA_IP_INTERMEDIATE'),
12311251
config.get('INTERMEDIATE_HOMEASSISTANT', 'HA_PORT_INTERMEDIATE'),
1252+
config.getboolean('INTERMEDIATE_HOMEASSISTANT', 'HA_HTTPS_INTERMEDIATE', fallback=False),
12321253
config.get('INTERMEDIATE_HOMEASSISTANT', 'HA_ACCESSTOKEN_INTERMEDIATE'),
12331254
config.get('INTERMEDIATE_HOMEASSISTANT', 'HA_CURRENT_POWER_ENTITY_INTERMEDIATE'),
12341255
config.getboolean('INTERMEDIATE_HOMEASSISTANT', 'HA_POWER_CALCULATE_INTERMEDIATE', fallback=False),
@@ -1306,6 +1327,7 @@ def CreateDTU() -> DTU:
13061327
SET_INVERTER_TO_MIN_ON_POWERMETER_ERROR = config.getboolean('COMMON', 'SET_INVERTER_TO_MIN_ON_POWERMETER_ERROR', fallback=False)
13071328
powermeter_target_point = config.getint('CONTROL', 'POWERMETER_TARGET_POINT')
13081329
SERIAL_NUMBER = []
1330+
ENABLED = []
13091331
NAME = []
13101332
TEMPERATURE = []
13111333
HOY_MAX_WATT = []
@@ -1326,6 +1348,7 @@ def CreateDTU() -> DTU:
13261348
HOY_BATTERY_AVERAGE_CNT = []
13271349
for i in range(INVERTER_COUNT):
13281350
SERIAL_NUMBER.append(config.get('INVERTER_' + str(i + 1), 'SERIAL_NUMBER', fallback=''))
1351+
ENABLED.append(config.getboolean('INVERTER_' + str(i + 1), 'ENABLED', fallback = True))
13291352
NAME.append(str('yet unknown'))
13301353
TEMPERATURE.append(str('--- degC'))
13311354
HOY_MAX_WATT.append(config.getint('INVERTER_' + str(i + 1), 'HOY_MAX_WATT'))

0 commit comments

Comments
 (0)