Skip to content

Commit

Permalink
Merge pull request #50 from henricm/ha-energy-support
Browse files Browse the repository at this point in the history
feat: add support for Home Assistant Home Energy Management
  • Loading branch information
argoyle authored Aug 4, 2021
2 parents 2ae6e26 + e7192e9 commit 9e5c233
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 26 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Ferroamp MQTT support sends updates to these topics:
* extapi/data/esm (interval 60s)

## Prerequisites
- Home assistant `2021.7`
- Home assistant `2021.8`
- Enable Ferroamp MQTT by contacting [Ferroamp Support](https://ferroamp.com/sv/kontakt/) to get the username and password for your Energy MQTT broker.
- Enable MQTT in Home assistant and set the broker to your Ferroamp Energy IP and configure it with your username and password received from Ferroamp (or setup a bridge-connection if you already have an MQTT-server, see the `Configuring Bridges`-section in the [Mosquitto documentation](https://mosquitto.org/man/mosquitto-conf-5.html)).

Expand Down
2 changes: 1 addition & 1 deletion custom_components/ferroamp/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"domain": "ferroamp",
"name": "Ferroamp MQTT Sensors",
"version": "0.1.1",
"version": "1.0.0",
"config_flow": true,
"documentation": "https://github.com/henricm/ha-ferroamp/",
"dependencies": [
Expand Down
98 changes: 77 additions & 21 deletions custom_components/ferroamp/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,29 @@
import uuid
from datetime import datetime

from homeassistant import config_entries, core
from homeassistant import config_entries, core, util
from homeassistant.components import mqtt
from homeassistant.components.sensor import (
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLTAGE,
SensorEntity,
STATE_CLASS_MEASUREMENT
)
from homeassistant.const import (
CONF_NAME,
CONF_PREFIX,
ELECTRICAL_CURRENT_AMPERE,
ELECTRIC_CURRENT_AMPERE,
ENERGY_KILO_WATT_HOUR,
ENERGY_WATT_HOUR,
FREQUENCY_HERTZ,
PERCENTAGE,
POWER_WATT,
TEMP_CELSIUS,
VOLT
ELECTRIC_POTENTIAL_VOLT
)
from homeassistant.core import callback
from homeassistant.helpers.entity_registry import async_get as async_get_entity_reg
Expand Down Expand Up @@ -352,7 +362,7 @@ def esm_event_received(msg):
config_id,
model=model
),
BatteryFerroampSensor(
PercentageFerroampSensor(
f"{device_name} State of Health",
"soh",
device_id,
Expand Down Expand Up @@ -518,7 +528,7 @@ async def options_update_listener(hass, entry):
sensor.handle_options_update(entry.options)


class FerroampSensor(RestoreEntity):
class FerroampSensor(SensorEntity, RestoreEntity):
"""Representation of a Ferroamp Sensor."""

def __init__(self, name, unit, icon, device_id, device_name, interval, config_id, **kwargs):
Expand All @@ -533,9 +543,21 @@ def __init__(self, name, unit, icon, device_id, device_name, interval, config_id
"model": kwargs.get("model")
}
self._attr_should_poll = False
if unit == ENERGY_KILO_WATT_HOUR:
self._attr_device_class = DEVICE_CLASS_ENERGY
elif unit == POWER_WATT:
self._attr_device_class = DEVICE_CLASS_POWER
elif unit == ELECTRIC_POTENTIAL_VOLT:
self._attr_device_class = DEVICE_CLASS_VOLTAGE
elif unit == ELECTRIC_CURRENT_AMPERE:
self._attr_device_class = DEVICE_CLASS_CURRENT
elif unit == TEMP_CELSIUS:
self._attr_device_class = DEVICE_CLASS_TEMPERATURE
self._interval = interval
self.device_id = device_id
self.config_id = config_id
self._attr_state_class = kwargs.get('state_class')
self._attr_last_reset = kwargs.get('last_reset')

async def async_added_to_hass(self) -> None:
"""Handle entity which will be added."""
Expand Down Expand Up @@ -648,7 +670,8 @@ class DcLinkFerroampSensor(KeyedFerroampSensor):

def __init__(self, name, key, icon, device_id, device_name, interval, config_id):
"""Initialize the sensor."""
super().__init__(name, key, VOLT, icon, device_id, device_name, interval, config_id)
super().__init__(name, key, ELECTRIC_POTENTIAL_VOLT, icon, device_id, device_name, interval, config_id)
self._attr_state_class = STATE_CLASS_MEASUREMENT

def get_voltage(self, event):
voltage = event.get(self._state_key, None)
Expand All @@ -670,11 +693,12 @@ def update_state_from_events(self, events):
pos=round(float(pos / len(events)), 2))


class BatteryFerroampSensor(FloatValFerroampSensor):
class PercentageFerroampSensor(FloatValFerroampSensor):
def __init__(self, name, key, device_id, device_name, interval, precision, config_id, **kwargs):
super().__init__(
name, key, PERCENTAGE, "mdi:battery-low", device_id, device_name, interval, precision, config_id, **kwargs
)
self._attr_state_class = STATE_CLASS_MEASUREMENT

def update_state_from_events(self, events):
super().update_state_from_events(events)
Expand All @@ -685,6 +709,14 @@ def update_state_from_events(self, events):
else:
self._attr_icon = "mdi:battery"


class BatteryFerroampSensor(PercentageFerroampSensor):
def __init__(self, name, key, device_id, device_name, interval, precision, config_id, **kwargs):
super().__init__(
name, key, device_id, device_name, interval, precision, config_id, **kwargs
)
self._attr_device_class = DEVICE_CLASS_BATTERY

def handle_options_update(self, options):
super().handle_options_update(options)
self._precision = options.get(CONF_PRECISION_BATTERY)
Expand All @@ -695,6 +727,7 @@ def __init__(self, name, key, device_id, device_name, interval, precision, confi
super().__init__(
name, key, TEMP_CELSIUS, "mdi:thermometer", device_id, device_name, interval, precision, config_id, **kwargs
)
self._attr_state_class = STATE_CLASS_MEASUREMENT

def handle_options_update(self, options):
super().handle_options_update(options)
Expand All @@ -706,7 +739,7 @@ def __init__(self, name, key, icon, device_id, device_name, interval, precision,
super().__init__(
name,
key,
ELECTRICAL_CURRENT_AMPERE,
ELECTRIC_CURRENT_AMPERE,
icon,
device_id,
device_name,
Expand All @@ -715,6 +748,7 @@ def __init__(self, name, key, icon, device_id, device_name, interval, precision,
config_id,
**kwargs
)
self._attr_state_class = STATE_CLASS_MEASUREMENT

def handle_options_update(self, options):
super().handle_options_update(options)
Expand All @@ -724,8 +758,9 @@ def handle_options_update(self, options):
class VoltageFerroampSensor(FloatValFerroampSensor):
def __init__(self, name, key, icon, device_id, device_name, interval, precision, config_id, **kwargs):
super().__init__(
name, key, VOLT, icon, device_id, device_name, interval, precision, config_id, **kwargs
name, key, ELECTRIC_POTENTIAL_VOLT, icon, device_id, device_name, interval, precision, config_id, **kwargs
)
self._attr_state_class = STATE_CLASS_MEASUREMENT

def handle_options_update(self, options):
super().handle_options_update(options)
Expand All @@ -749,6 +784,7 @@ def __init__(self, name, key, icon, device_id, device_name, interval, precision,
config_id,
**kwargs
)
self._attr_state_class = STATE_CLASS_MEASUREMENT

def update_state_from_events(self, events):
temp = 0
Expand Down Expand Up @@ -816,6 +852,7 @@ def __init__(self, name, voltage_key, current_key, icon, device_id, device_name,
self._voltage_key = voltage_key
self._current_key = current_key
self._attr_unique_id = f"{self.device_id}-{self._voltage_key}-{self._current_key}"
self._attr_state_class = STATE_CLASS_MEASUREMENT

def update_state_from_events(self, events):
temp_voltage = temp_current = 0
Expand All @@ -834,9 +871,10 @@ def update_state_from_events(self, events):
class ThreePhaseFerroampSensor(KeyedFerroampSensor):
"""Representation of a Ferroamp ThreePhase Sensor."""

def __init__(self, name, key, unit, icon, device_id, device_name, interval, precision, config_id):
def __init__(self, name, key, unit, icon, device_id, device_name, interval, precision, config_id, **kwargs):
"""Initialize the sensor."""
super().__init__(name, key, unit, icon, device_id, device_name, interval, config_id)
super().__init__(name, key, unit, icon, device_id, device_name, interval, config_id, **kwargs)
self._attr_state_class = STATE_CLASS_MEASUREMENT
self._precision = precision

def get_phases(self, event):
Expand Down Expand Up @@ -868,9 +906,21 @@ def update_state_from_events(self, events):


class ThreePhaseEnergyFerroampSensor(ThreePhaseFerroampSensor):
def __init__(self, name, key, icon, device_id, device_name, interval, precision, config_id):
def __init__(self, name, key, icon, device_id, device_name, interval, precision, config_id, **kwargs):
"""Initialize the sensor."""
super().__init__(name, key, ENERGY_KILO_WATT_HOUR, icon, device_id, device_name, interval, precision, config_id)
super().__init__(
name,
key,
ENERGY_KILO_WATT_HOUR,
icon,
device_id,
device_name,
interval,
precision,
config_id,
**kwargs
)
self._attr_state_class = STATE_CLASS_MEASUREMENT

def get_phases(self, event):
phases = super().get_phases(event)
Expand All @@ -892,6 +942,7 @@ class ThreePhasePowerFerroampSensor(ThreePhaseFerroampSensor):
def __init__(self, name, key, icon, device_id, device_name, interval, config_id):
"""Initialize the sensor."""
super().__init__(name, key, POWER_WATT, icon, device_id, device_name, interval, 0, config_id)
self._attr_state_class = STATE_CLASS_MEASUREMENT


class CommandFerroampSensor(FerroampSensor):
Expand Down Expand Up @@ -980,7 +1031,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
ThreePhaseFerroampSensor(
f"{name} External Voltage",
"ul",
VOLT,
ELECTRIC_POTENTIAL_VOLT,
"mdi:current-ac",
f"{slug}_{EHUB}",
f"{name} {EHUB_NAME}",
Expand All @@ -991,7 +1042,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
ThreePhaseFerroampSensor(
f"{name} Inverter RMS current",
"il",
ELECTRICAL_CURRENT_AMPERE,
ELECTRIC_CURRENT_AMPERE,
"mdi:current-dc",
f"{slug}_{EHUB}",
f"{name} {EHUB_NAME}",
Expand All @@ -1002,7 +1053,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
ThreePhaseFerroampSensor(
f"{name} Inverter reactive current",
"ild",
ELECTRICAL_CURRENT_AMPERE,
ELECTRIC_CURRENT_AMPERE,
"mdi:current-dc",
f"{slug}_{EHUB}",
f"{name} {EHUB_NAME}",
Expand All @@ -1013,7 +1064,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
ThreePhaseFerroampSensor(
f"{name} Grid Current",
"iext",
ELECTRICAL_CURRENT_AMPERE,
ELECTRIC_CURRENT_AMPERE,
"mdi:current-ac",
f"{slug}_{EHUB}",
f"{name} {EHUB_NAME}",
Expand All @@ -1024,7 +1075,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
ThreePhaseFerroampSensor(
f"{name} Grid Reactive Current",
"iextd",
ELECTRICAL_CURRENT_AMPERE,
ELECTRIC_CURRENT_AMPERE,
"mdi:current-ac",
f"{slug}_{EHUB}",
f"{name} {EHUB_NAME}",
Expand All @@ -1035,7 +1086,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
ThreePhaseFerroampSensor(
f"{name} External Active Current",
"iextq",
ELECTRICAL_CURRENT_AMPERE,
ELECTRIC_CURRENT_AMPERE,
"mdi:current-ac",
f"{slug}_{EHUB}",
f"{name} {EHUB_NAME}",
Expand All @@ -1046,7 +1097,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
ThreePhaseFerroampSensor(
f"{name} Adaptive Current Equalization",
"iace",
ELECTRICAL_CURRENT_AMPERE,
ELECTRIC_CURRENT_AMPERE,
"mdi:current-ac",
f"{slug}_{EHUB}",
f"{name} {EHUB_NAME}",
Expand Down Expand Up @@ -1117,6 +1168,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
interval,
precision_energy,
config_id,
last_reset=util.dt.utc_from_timestamp(0),
),
ThreePhaseEnergyFerroampSensor(
f"{name} External Energy Consumed",
Expand All @@ -1127,6 +1179,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
interval,
precision_energy,
config_id,
last_reset=util.dt.utc_from_timestamp(0),
),
ThreePhaseEnergyFerroampSensor(
f"{name} Inverter Energy Produced",
Expand Down Expand Up @@ -1177,6 +1230,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
interval,
precision_energy,
config_id,
last_reset=util.dt.utc_from_timestamp(0),
),
EnergyFerroampSensor(
f"{name} Battery Energy Produced",
Expand Down Expand Up @@ -1226,7 +1280,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
precision_battery,
config_id,
),
BatteryFerroampSensor(
PercentageFerroampSensor(
f"{name} System State of Health",
"soh",
f"{slug}_{EHUB}",
Expand All @@ -1253,6 +1307,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
f"{name} {EHUB_NAME}",
interval,
config_id,
state_class=STATE_CLASS_MEASUREMENT,
),
PowerFerroampSensor(
f"{name} Battery Power",
Expand All @@ -1262,6 +1317,7 @@ def ehub_sensors(slug, name, interval, precision_battery, precision_energy, prec
f"{name} {EHUB_NAME}",
interval,
config_id,
state_class=STATE_CLASS_MEASUREMENT
),
IntValFerroampSensor(
f"{name} Total rated capacity of all batteries",
Expand Down
2 changes: 1 addition & 1 deletion hacs.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"name": "Ferroamp Sensors",
"homeassistant": "2021.6"
"homeassistant": "2021.8.0b1"
}
4 changes: 2 additions & 2 deletions requirements.test.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Strictly for tests
pytest==6.2.4
pytest-cov<3.0.0
pytest-homeassistant-custom-component==0.4.2
pytest-homeassistant-custom-component==0.4.3
# From our manifest.json for our custom component
aiohttp_cors==0.7.0
paho-mqtt==1.5.1

homeassistant==2021.7.0b0
homeassistant==2021.8.0b0
voluptuous==0.12.1
Loading

0 comments on commit 9e5c233

Please sign in to comment.