Skip to content

Commit

Permalink
feat: use Wibeee device name to assign Home Assistant name (#18)
Browse files Browse the repository at this point in the history
* refactor: remove unused definitions

* feat: use Device Name to assign HA name separately from entity ID

* doc: update sensor names in REAME
  • Loading branch information
luuuis authored Dec 19, 2021
1 parent 6474db6 commit da3174c
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 65 deletions.
41 changes: 22 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,24 @@ Integrates CIRCUTOR Wibeee/Mirubeee energy monitoring devices into Home Assistan
with single and three-phase versions.

### Sensors
Provides the following sensors, one for each phase (`Phase1` shown below).

| Sensor | Unit | Description |
| -------------------------------------------|:------:|------------------|
| `wibeee_phase1_active_energy` | Wh | Active Energy |
| `wibeee_phase1_active_power` | W | Active Power |
| `wibeee_phase1_apparent_power` | VA | Apparent Power |
| `wibeee_phase1_capacitive_reactive_energy` | VArCh | Capacitive Reactive Energy |
| `wibeee_phase1_capacitive_reactive_power` | VArC | Capacitive Reactive Power |
| `wibeee_phase1_frequency` | Hz | Frequency |
| `wibeee_phase1_inductive_reactive_energy` | VArLh | Inductive Reactive Energy |
| `wibeee_phase1_inductive_reactive_power` | VArL | Inductive Reactive Power |
| `wibeee_phase1_irms` | A | Current |
| `wibeee_phase1_power_factor` | PF | Power Factor |
| `wibeee_phase1_vrms` | V | Phase Voltage |

In three-phased devices `Phase4` sensors contain the total readings across all three phases.

Provides the following sensors, one for each clamp using `_L1`/`_L2`/`_L3` suffixes.

| Sensor | Unit | Description |
| -----------------------------------------------|:------:|------------------|
| `wibeee_<mac_addr>_active_energy` | Wh | Active Energy |
| `wibeee_<mac_addr>_active_power` | W | Active Power |
| `wibeee_<mac_addr>_apparent_power` | VA | Apparent Power |
| `wibeee_<mac_addr>_capacitive_reactive_energy` | VArCh | Capacitive Reactive Energy |
| `wibeee_<mac_addr>_capacitive_reactive_power` | VArC | Capacitive Reactive Power |
| `wibeee_<mac_addr>_frequency` | Hz | Frequency |
| `wibeee_<mac_addr>_inductive_reactive_energy` | VArLh | Inductive Reactive Energy |
| `wibeee_<mac_addr>_inductive_reactive_power` | VArL | Inductive Reactive Power |
| `wibeee_<mac_addr>_current` | A | Current |
| `wibeee_<mac_addr>_power_factor` | PF | Power Factor |
| `wibeee_<mac_addr>_phase_voltage` | V | Phase Voltage |

In three-phase devices the `_L4` sensors contain the total readings across all phases.

## Installation

Expand Down Expand Up @@ -56,8 +57,10 @@ of the energy monitor on your network.
```yaml
sensor:
- platform: wibeee
host: 192.168.xx.xx # use static IP
scan_interval: 15 # optional, defaults to 15 seconds
host: 192.168.1.xx # use static IP
scan_interval: 15 # optional, defaults to 15 seconds
- platform: wibeee
host: 192.168.1.yy # add a second device
```

Optionally, configure extra template sensors for grid consumption and feed-in to use
Expand Down
70 changes: 24 additions & 46 deletions custom_components/wibeee/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,9 @@
import logging
import voluptuous as vol
from datetime import timedelta
from urllib.parse import quote_plus

import requests
# noinspection PyUnresolvedReferences
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

from homeassistant.util import slugify
import homeassistant.helpers.config_validation as cv
from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
Expand Down Expand Up @@ -56,17 +52,10 @@

_LOGGER = logging.getLogger(__name__)

BASE_URL = 'http://{0}:{1}/{2}'
PORT = 80
API_PATH = 'en/status.xml'

DOMAIN = 'wibeee_energy'
DEFAULT_NAME = 'Wibeee Energy Consumption Sensor'
DEFAULT_HOST = ''
DEFAULT_RESOURCE = 'http://{}/en/status.xml'
DEFAULT_SCAN_INTERVAL = timedelta(seconds=15)
DEFAULT_TIMEOUT = timedelta(seconds=10)
DEFAULT_PHASES = 3

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
Expand Down Expand Up @@ -119,36 +108,22 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=
class WibeeeSensor(SensorEntity):
"""Implementation of Wibeee sensor."""

def __init__(self, wibeee_data, mac_addr, sensor_id, sensor_phase, status_xml_name, sensor_value):
def __init__(self, wibeee_data, device, sensor_id, sensor_phase, status_xml_name, sensor_value):
"""Initialize the sensor."""
ha_name, friendly_name, unit, device_class = SENSOR_TYPES[status_xml_name]
[device_name, mac_addr] = [device['id'], device['mac_addr']] if device else ["Wibeee", None]
entity_id = slugify(f"Wibeee {mac_addr} {friendly_name} L{sensor_phase}" if mac_addr else f"wibeee_Phase{sensor_phase}_{ha_name}")
self._wibeee_data = wibeee_data
self._entity = sensor_id
self._unit_of_measurement = unit
self._state = sensor_value
self._attr_state = sensor_value
self._attr_available = True
self._attr_state_class = STATE_CLASS_MEASUREMENT
self._attr_device_class = device_class
if mac_addr:
self._attr_unique_id = f"wibeee_{mac_addr}_{ha_name.lower()}_{sensor_phase}"
self._attr_name = f"Wibeee {mac_addr.upper()} {friendly_name} L{sensor_phase}"
else:
self._attr_name = f"wibeee_Phase{sensor_phase}_{ha_name}"

@property
def state(self):
"""Return the state of the device."""
return self._state

@property
def unit_of_measurement(self):
"""Return the unit the value is expressed in."""
return self._unit_of_measurement

@property
def should_poll(self):
"""No polling needed."""
return False
self._attr_unique_id = f"wibeee_{mac_addr}_{ha_name.lower()}_{sensor_phase}" if mac_addr else None
self._attr_name = f"{device_name} {friendly_name} L{sensor_phase}"
self._attr_should_poll = False
self.entity_id = f"sensor.{entity_id}" # we don't want this derived from the name


class WibeeeData(object):
Expand All @@ -175,14 +150,17 @@ async def async_fetch_status(self, retries=0):
status = await self.async_fetch_url(f'http://{self.host}/en/status.xml', retries)
return status["response"]

async def async_fetch_mac_addr(self, retries):
async def async_fetch_device_info(self, retries):
try:
# <devices><id>WIBEEE</id></devices>
devices = await self.async_fetch_url(f'http://{self.host}/services/user/devices.xml', retries)
device_id = devices['devices']['id']
# <values><variable><id>macAddr</id><value>11:11:11:11:11:11</value></variable></values>
response = await self.async_fetch_url(f'http://{self.host}/services/user/values.xml?var=WIBEEE.macAddr', retries)
value = response['values']['variable']['value']
return value.replace(":", "").lower() if value else None
values = await self.async_fetch_url(f'http://{self.host}/services/user/values.xml?var={quote_plus(device_id)}.macAddr', retries)
mac_addr = values['values']['variable']['value']
return dict(id=device_id, mac_addr=mac_addr.replace(":", "").lower()) if device_id and mac_addr else None
except Exception:
_LOGGER.warning("Error getting MAC address, sensors will not have a unique ID", exc_info=True)
_LOGGER.warning("Error getting device info, sensors will not have a unique ID", exc_info=True)
return None

async def async_fetch_url(self, url, retries=0):
Expand Down Expand Up @@ -221,8 +199,8 @@ async def fetch_with_retries(try_n):

async def set_sensors(self):
"""Make first Get call to Initialize sensor names"""
device = await self.async_fetch_device_info(retries=5) if self.unique_id else None
status = await self.async_fetch_status(retries=10)
mac_addr = await self.async_fetch_mac_addr(retries=5) if self.unique_id else None

# Create tmp sensor array
tmp_sensors = []
Expand All @@ -236,11 +214,11 @@ async def set_sensors(self):
sensor_value = value

if sensor_name in SENSOR_TYPES:
sensor = WibeeeSensor(self, mac_addr, sensor_id, sensor_phase, sensor_name, sensor_value)
sensor = WibeeeSensor(self, device, sensor_id, sensor_phase, sensor_name, sensor_value)
_LOGGER.debug("Adding entity '%s' (uid=%s)", sensor.name, sensor.unique_id)
tmp_sensors.append(sensor)
except:
_LOGGER.error(f"Unable to create WibeeeSensor Entities for key {key} and value {value}")
_LOGGER.error(f"Unable to create WibeeeSensor Entities for key {key} and value {value}", exc_info=True)

# Add sensors
self.sensors = tmp_sensors
Expand All @@ -260,7 +238,7 @@ def updating_sensors(self, sensor_data):
"""Update all sensor states from sensor_data."""
for sensor in self.sensors:
if sensor.enabled:
sensor._state = sensor_data.get(sensor._entity, STATE_UNAVAILABLE)
sensor._attr_available = sensor._state is not STATE_UNAVAILABLE
sensor._attr_state = sensor_data.get(sensor._entity, STATE_UNAVAILABLE)
sensor._attr_available = sensor.state is not STATE_UNAVAILABLE
sensor.async_schedule_update_ha_state()
_LOGGER.debug("[sensor:%s] %s%s", sensor._entity, sensor._state, '' if sensor.enabled else ' (DISABLED)')
_LOGGER.debug("[sensor:%s] %s%s", sensor._entity, sensor.state, '' if sensor.enabled else ' (DISABLED)')

0 comments on commit da3174c

Please sign in to comment.