Skip to content

Commit

Permalink
feat: BleBox Multisensor Illuminance Integration (#161)
Browse files Browse the repository at this point in the history
* BleBox Multisensor Illuminance Integration
  • Loading branch information
Pastucha authored Mar 13, 2024
1 parent c5bc2cf commit dbd5e11
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,4 @@ ENV/
.mypy_cache/

# IDE settings
.vscode/
.vscode/
24 changes: 24 additions & 0 deletions blebox_uniapi/box_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,30 @@ def get_latest_api_level(product_type: str) -> Union[dict, int]:
},
},
"multiSensor": {
20220114: {
"api_path": "/state",
"extended_state_path": "/state/extended",
"sensors": [
[
"multiSensor",
{
"illuminance": lambda x: f"multiSensor/sensors/[id={x}]/value",
"temperature": lambda x: f"multiSensor/sensors/[id={x}]/value",
"wind": lambda x: f"multiSensor/sensors/[id={x}]/value",
"humidity": lambda x: f"multiSensor/sensors/[id={x}]/value",
},
]
],
"binary_sensors": [
[
"multiSensor",
{
"rain": lambda x: f"multiSensor/sensors/[id={x}]/value",
"flood": lambda x: f"multiSensor/sensors/[id={x}]/value",
},
]
],
},
20210413: {
"api_path": "/state",
"extended_state_path": "/state/extended",
Expand Down
1 change: 1 addition & 0 deletions blebox_uniapi/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class UnifiedCoverType(IntEnum):
can be infered from internal device information end exposed to library user.
"""

AWNING = auto()
BLIND = auto()
CURTAIN = auto()
Expand Down
22 changes: 22 additions & 0 deletions blebox_uniapi/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,26 @@ def many_from_config(cls, product, box_type_config, extended_state):
raise NotImplementedError("Please use SensorFactory")


class Illuminance(BaseSensor):
def __init__(self, product: "Box", alias: str, methods: dict):
super().__init__(product, alias, methods)
self._unit = "lx"
self._device_class = "illuminance"

def _read_illuminance(self):
product = self._product
if product.last_data is not None:
raw = self.raw_value("illuminance")
if raw is not None:
alias = self._alias
return round(product.expect_int(alias, raw, 10000000, 0) / 100.0, 1)
# 100000, 0 is a representation of illuminance range in lx in mili (it should be devided by 100 like temprature)
return None

def after_update(self) -> None:
self._native_value = self._read_illuminance()


class Temperature(BaseSensor):
_current: Union[float, int, None]

Expand Down Expand Up @@ -93,6 +113,7 @@ def _read_humidity(self, field: str) -> Optional[int]:
if raw is not None:
alias = self._alias
return round(product.expect_int(alias, raw, 10000, 0) / 100.0, 1)

return None

def after_update(self) -> None:
Expand Down Expand Up @@ -162,6 +183,7 @@ def many_from_config(
"temperature": Temperature,
"humidity": Humidity,
"wind": Wind,
"illuminance": Illuminance,
}
if extended_state:
object_list = list()
Expand Down
86 changes: 86 additions & 0 deletions docs/howtoaddsensor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@


Integration for Blebox devices in Home Assistant.
=============

This documentation assumes you are familiar with Home Assistant and the Blebox devices.

How to Add a New Sensor (Based on MultiSensor Illuminance)
--------------------------------------------------------

1. **Update SENSOR_TYPES tuple in homeassistant.components.blebox.sensor module to allow creation of proper homeassistant entities for light readings depending on device capability reported by blebox_uniapi library.**:


```python
from homeassistant.components.blebox.sensor import SensorEntityDescription, SensorDeviceClass
from homeassistant.const import LIGHT_LUX

SENSOR_TYPES = (
# ... (existing entries)

SensorEntityDescription(
key="illuminance",
device_class=SensorDeviceClass.ILLUMINANCE,
native_unit_of_measurement=LIGHT_LUX,
),
)```
2. **Update box_types module in blebox_uniapi to support new sensor types. (API level will be given, use newest version of the sensor if u want to copy paste)**
```python
"multiSensor": {
20220114: {
"api_path": "/state",
"extended_state_path": "/state/extended",
"sensors": [
[
"multiSensor",
{
"illuminance": lambda x:f"multiSensor/sensors/[id={x}]/value",
"temperature": lambda x: f"multiSensor/sensors/[id={x}]/value",
"wind": lambda x: f"multiSensor/sensors/[id={x}]/value",
"humidity": lambda x: f"multiSensor/sensors/[id={x}]/value",
},
]
],
"binary_sensors": [
[
"multiSensor",
{
"rain": lambda x: f"multiSensor/sensors/[id={x}]/value",
"flood": lambda x: f"multiSensor/sensors/[id={x}]/value",
},
]
],
},
```
3. **Create new sensor class in blebox_uniapi.sensor module for light related readings updating type_class_mapper in blebox_uniapi.sensor.SensorFactory to return proper sensor class if device supports light related measurements**

```python
class Illuminance(BaseSensor):
def __init__(self, product: "Box", alias: str, methods: dict):
super().__init__(product, alias, methods)
self._unit = "lx"
self._device_class = "illuminance"

def _read_illuminance(self):
product = self._product
if product.last_data is not None:
raw = self.raw_value("illuminance")
if raw is not None:
alias = self._alias
return round(product.expect_int(alias, raw, 100000, 0)/100.0, 1)
return None
```
```python
class SensorFactory:
@classmethod
def many_from_config(
cls, product, box_type_config, extended_state
) -> list["BaseSensor"]:
type_class_mapper = {
"airSensor": AirQuality,
"temperature": Temperature,
"humidity": Humidity,
"wind": Wind,
"illuminance" : Illuminance
}
```
7 changes: 3 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,13 @@ async def allow_get_info(self, aioclient_mock, info=None):
json_get_expect(
aioclient_mock, f"http://{self.IP}:80/api/device/state", json=data
)
if (
(hasattr(self, "DEVICE_EXTENDED_INFO")) and
(path := getattr(self, "DEVICE_EXTENDED_INFO_PATH"))
if (hasattr(self, "DEVICE_EXTENDED_INFO")) and (
path := getattr(self, "DEVICE_EXTENDED_INFO_PATH")
):
data = self.DEVICE_EXTENDED_INFO or info
json_get_expect(
aioclient_mock,
f"http://{self.IP}:80/{path.lstrip('/')}",
f"http://{self.IP}:80/{path.lstrip('/')}",
json=data,
)

Expand Down
2 changes: 1 addition & 1 deletion tests/test_light.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ async def test_init(self, aioclient_mock):

assert entity.name == "My wLightBoxS (wLightBoxS#brightness_mono1)"
assert entity.unique_id == "BleBox-wLightBoxS-1afe34e750b8-brightness_mono1"
assert entity.brightness == 0xf5
assert entity.brightness == 0xF5
assert entity.is_on

async def test_device_info(self, aioclient_mock):
Expand Down

0 comments on commit dbd5e11

Please sign in to comment.