Skip to content

Commit

Permalink
Single config entry setup (#2)
Browse files Browse the repository at this point in the history
- now integration setups with single sensor entry
- global code refactoring
  • Loading branch information
odya authored Nov 2, 2023
1 parent 97c31a9 commit d3e86f6
Show file tree
Hide file tree
Showing 10 changed files with 316 additions and 288 deletions.
28 changes: 6 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,6 @@ In the end your file structure should look like that:
```

## Configuration
### Example configuration package
You can use preconfigured integration package if your HA instance is configured to use packages.
You can check it by presence of `packages` directory in config folder and such code in `configuration.yaml`:
```yaml
homeassistant:
packages: !include_dir_merge_named packages
```
After that you can copy file [ina219_ups_hat.yaml](/examples/packages/ina219_ups_hat.yaml) to your `packages` folder & customize it.

### Example automations
Copy contents of [examples/automations.yaml](/examples/automations.yaml) to your `automations.yaml`. Customize.

### Sensor
Create a new sensor entry in your `configuration.yaml`

Expand All @@ -55,16 +43,17 @@ sensor:
batteries_count: 3 # Optional
max_soc: 91 # Optional
battery_capacity: 9000 # Optional
sma_samples: 5 # Optional
```
Following data can be read:
- SoC (State of Charge)
- PSU Voltage
- Shunt Voltage
- Voltage
- Current
- Power
- Charging Status
- Online Status
- Is Low Battery (< 20%)
- Remaining Capacity
- Remaining Time
If you consistently experience capacity below 100% when the device is fully charged, you can adjust it using the `max_soc` property.

Expand All @@ -89,13 +78,8 @@ sensor:
#### Batteries Count
The original Waveshare UPS Hat has 2 batteries in series (8.4V), but some versions of the UPS Hats may have 3 batteries (12.6V). If you have more than 2 batteries in series, use the `batteries_count` parameter.

### Binary Sensor
In addition to the sensor devices, you may also create a device which is simply “on” when the UPS status is online and “off” at all other times.

```yaml
binary_sensor:
- platform: ina219_ups_hat
```
### Example automations
Copy contents of [examples/automations.yaml](/examples/automations.yaml) to your `automations.yaml`. Customize.

## Directions for installing smbus support on Raspberry Pi

Expand Down
2 changes: 1 addition & 1 deletion custom_components/ina219_ups_hat/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"""Waveshare INA219 UPS Hat"""
"""INA219 UPS Hat"""
56 changes: 0 additions & 56 deletions custom_components/ina219_ups_hat/binary_sensor.py

This file was deleted.

25 changes: 25 additions & 0 deletions custom_components/ina219_ups_hat/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,28 @@
MIN_CHARGING_CURRENT = 1
MIN_BATTERY_CONNECTED_CURRENT = 0.1
LOW_BATTERY_PERCENTAGE = 20

DOMAIN = "ina219_ups_hat"
DEFAULT_NAME = "ina219_ups_hat"

CONF_BATTERY_CAPACITY = "battery_capacity"
CONF_MAX_SOC = "max_soc"
CONF_SMA_SAMPLES = "sma_samples"
CONF_BATTERIES_COUNT = "batteries_count"
CONF_SCAN_INTERVAL = "scan_interval"

ATTR_CAPACITY = "capacity"
ATTR_SOC = "soc"
ATTR_REAL_SOC = "real_soc"
ATTR_PSU_VOLTAGE = "psu_voltage"
ATTR_SHUNT_VOLTAGE = "shunt_voltage"
ATTR_LOAD_VOLTAGE = "load_voltage"
ATTR_CURRENT = "current"
ATTR_POWER = "power"
ATTR_CHARGING = "charging"
ATTR_ONLINE = "online"
ATTR_BATTERY_CONNECTED = "battery_connected"
ATTR_LOW_BATTERY = "low_battery"
ATTR_POWER_CALCULATED = "power_calculated"
ATTR_REMAINING_BATTERY_CAPACITY = "remaining_battery_capacity"
ATTR_REMAINING_TIME = "remaining_time_min"
93 changes: 93 additions & 0 deletions custom_components/ina219_ups_hat/coordinator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import logging
from .const import CONF_BATTERIES_COUNT, CONF_BATTERY_CAPACITY, CONF_MAX_SOC, CONF_SMA_SAMPLES, MIN_CHARGING_CURRENT, MIN_ONLINE_CURRENT
from .ina219 import INA219
from .ina219_wrapper import INA219Wrapper
from homeassistant import core
from homeassistant.const import CONF_NAME, CONF_UNIQUE_ID
from homeassistant.helpers.typing import ConfigType
from homeassistant.helpers.update_coordinator import (
DataUpdateCoordinator,
UpdateFailed,
)
import random

_LOGGER = logging.getLogger(__name__)


class INA219UpsHatCoordinator(DataUpdateCoordinator):
def __init__(self, hass: core.HomeAssistant, config: ConfigType) -> None:
"""Initialize coordinator"""

self.name_prefix = config.get(CONF_NAME)
self.id_prefix = config.get(CONF_UNIQUE_ID)

self._max_soc = config.get(CONF_MAX_SOC)
self._battery_capacity = config.get(CONF_BATTERY_CAPACITY)
self._batteries_count = config.get(CONF_BATTERIES_COUNT)
self._sma_samples = config.get(CONF_SMA_SAMPLES)

self._ina219 = INA219(addr=0x41)
self._ina219_wrapper = INA219Wrapper(self._ina219, self._sma_samples)

super().__init__(
hass,
_LOGGER,
name="ina219_ups_hat",
update_method=self._update_data,
)

async def _update_data(self):
try:
ina219_wrapper = self._ina219_wrapper
ina219_wrapper.measureINAValues()

bus_voltage = ina219_wrapper.getBusVoltageSMA_V() # voltage on V- (load side)
shunt_voltage = (ina219_wrapper.getShuntVoltageSMA_mV() / 1000) # voltage between V+ and V- across the shunt
current = ina219_wrapper.getCurrentSMA_mA() # current in mA
power = ina219_wrapper.getPowerSMA_W() # power in W

smooth_bus_voltage = ina219_wrapper.getBusVoltageSMAx2_V()
smooth_current = ina219_wrapper.getCurrentSMAx2_mA()

soc_c1 = 3 * self._batteries_count
soc_c2 = 1.2 * self._batteries_count
real_soc = (smooth_bus_voltage - soc_c1) / soc_c2 * 100
soc = (
(smooth_bus_voltage - soc_c1) /
(soc_c2 * (self._max_soc / 100.0)) * 100
)
if soc > 100:
soc = 100
if soc < 0:
soc = 0

power_calculated = bus_voltage * (current / 1000)

online = bool(current > MIN_ONLINE_CURRENT)
charging = bool(current > MIN_CHARGING_CURRENT)

if self._battery_capacity is None:
remaining_battery_capacity = None
remaining_time = None
else:
remaining_battery_capacity = (
real_soc / 100.0) * self._battery_capacity
if not online:
remaining_time = round(
(remaining_battery_capacity / -smooth_current) * 60.0, 0
)
else:
remaining_time = None

return {
"voltage": round(bus_voltage + shunt_voltage, 2),
"current": round(current / 1000, 5),
"power": round(power_calculated, 2),
"soc": round(soc, 1),
"remaining_battery_capacity": round(remaining_battery_capacity, 0),
"remaining_time": remaining_time,
"online": online,
"charging": charging,
}
except Exception as e:
raise UpdateFailed(f"Error updating data: {e}")
31 changes: 31 additions & 0 deletions custom_components/ina219_ups_hat/entity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

from .const import DOMAIN
from .coordinator import INA219UpsHatCoordinator
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo


class INA219UpsHatEntity():
def __init__(self, coordinator: INA219UpsHatCoordinator) -> None:
self._coordinator = coordinator
self._device_id = self._coordinator.id_prefix

@property
def name(self):
return self._coordinator.name_prefix + ' ' + self._name

@property
def unique_id(self):
return self._coordinator.id_prefix + '_' + self._name

@property
def device_info(self) -> DeviceInfo:
"""Return the device_info of the device."""
return DeviceInfo(
identifiers={(DOMAIN, self._coordinator.id_prefix)},
name=self._coordinator.name_prefix,
manufacturer="Some Chinese factory",
sw_version="0.3.0",
)

async def async_update(self):
await self._coordinator.async_request_refresh()
4 changes: 2 additions & 2 deletions custom_components/ina219_ups_hat/ina219_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def _getSMMValue(self, buf:deque, divider:int=1):
return np.median(self._getBufTail(buf, divider))
return np.median(buf)

def _getBufTail(self, buf:deque, divider:int):
slice_start = len(buf) - int(len(buf) / divider)
def _getBufTail(self, buf: deque, divider: int):
slice_start = len(buf) - int(len(buf) / divider) - 1
slice_end = len(buf)
return list(buf)[slice_start:slice_end]
2 changes: 1 addition & 1 deletion custom_components/ina219_ups_hat/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/odya/hass-ina219-ups-hat/issues",
"requirements": ["smbus2>=0.4.2","numpy>=1.23.2"],
"version": "0.2.1"
"version": "0.3.0"
}
Loading

0 comments on commit d3e86f6

Please sign in to comment.