forked from platypush/platypush
Rewritten vl53l1x integration as a runnable plugin with entity support
This commit is contained in:
parent
226034946f
commit
a3e8c7c155
2 changed files with 130 additions and 43 deletions
|
@ -1,49 +1,84 @@
|
||||||
import time
|
from contextlib import contextmanager
|
||||||
|
from threading import RLock
|
||||||
|
from typing import List, Mapping
|
||||||
|
from typing_extensions import override
|
||||||
|
|
||||||
from platypush.plugins import action
|
from platypush.context import get_bus
|
||||||
from platypush.plugins.gpio.sensor import GpioSensorPlugin
|
from platypush.entities.managers.sensors import SensorEntityManager
|
||||||
|
from platypush.entities.devices import Device
|
||||||
|
from platypush.entities.distance import DistanceSensor
|
||||||
|
from platypush.message.event.sensor import SensorDataChangeEvent
|
||||||
|
from platypush.plugins import RunnablePlugin, action
|
||||||
|
from platypush.utils import get_plugin_name_by_class
|
||||||
|
|
||||||
|
|
||||||
class GpioSensorDistanceVl53L1XPlugin(GpioSensorPlugin):
|
class SensorDistanceVl53l1xPlugin(RunnablePlugin, SensorEntityManager):
|
||||||
"""
|
"""
|
||||||
Plugin to interact with an `VL53L1x <https://www.st.com/en/imaging-and-photonics-solutions/vl53l1x.html>`_
|
Plugin to interact with an `VL53L1x
|
||||||
|
<https://www.st.com/en/imaging-and-photonics-solutions/vl53l1x.html>`_
|
||||||
laser ranger/distance sensor
|
laser ranger/distance sensor
|
||||||
|
|
||||||
Requires:
|
Requires:
|
||||||
|
|
||||||
* ``smbus2`` (``pip install smbus2``)
|
* ``smbus2`` (``pip install smbus2``)
|
||||||
* ``vl53l1x`` (``pip install vl53l1x``)
|
* ``vl53l1x`` (``pip install vl53l1x``)
|
||||||
|
|
||||||
|
Triggers:
|
||||||
|
|
||||||
|
* :class:`platypush.message.event.sensor.SensorDataChangeEvent`
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, i2c_bus=1, i2c_address=0x29, **kwargs):
|
def __init__(self, i2c_bus=1, i2c_address=0x29, poll_interval=3, **kwargs):
|
||||||
"""
|
"""
|
||||||
:param i2c_bus: I2C bus number (default: 1)
|
:param i2c_bus: I2C bus number (default: 1)
|
||||||
:param i2c_address: I2C address (default: 0x29)
|
:param i2c_address: I2C address (default: 0x29)
|
||||||
|
:param poll_interval: How often the integration should poll for new
|
||||||
|
measurements (default: 3 seconds).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(**kwargs)
|
super().__init__(poll_interval=poll_interval, **kwargs)
|
||||||
|
|
||||||
self.i2c_bus = i2c_bus
|
self.i2c_bus = i2c_bus
|
||||||
self.i2c_address = i2c_address
|
self.i2c_address = i2c_address
|
||||||
self._device = None
|
self._device = None
|
||||||
|
self._device_lock = RLock()
|
||||||
|
self._last_data = {}
|
||||||
|
|
||||||
# noinspection PyUnresolvedReferences
|
@contextmanager
|
||||||
def _get_device(self, ranging=1):
|
def _get_device(self, ranging=1):
|
||||||
if self._device:
|
from VL53L1X import VL53L1X # type: ignore
|
||||||
return self._device
|
|
||||||
|
with self._device_lock:
|
||||||
|
if self._device:
|
||||||
|
yield self._device
|
||||||
|
|
||||||
from VL53L1X import VL53L1X
|
|
||||||
self._device = VL53L1X(i2c_bus=self.i2c_bus, i2c_address=self.i2c_address)
|
self._device = VL53L1X(i2c_bus=self.i2c_bus, i2c_address=self.i2c_address)
|
||||||
|
|
||||||
|
try:
|
||||||
self._device.open()
|
self._device.open()
|
||||||
self._device.start_ranging(ranging)
|
self._device.start_ranging(ranging)
|
||||||
return self._device
|
yield self._device
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
self._device.stop_ranging()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self._device.close()
|
||||||
|
self._device = None
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def get_measurement(self, short=True, medium=False, long=False):
|
@override
|
||||||
|
def status(self, *_, **__):
|
||||||
|
self.publish_entities(self._last_data)
|
||||||
|
return self._last_data
|
||||||
|
|
||||||
|
def _status(self, *_, short=True, medium=True, long=True, **__):
|
||||||
"""
|
"""
|
||||||
:param short: Enable short range measurement (default: True)
|
:param short: Enable short range measurement (default: True)
|
||||||
:param medium: Enable medium range measurement (default: False)
|
:param medium: Enable medium range measurement (default: True)
|
||||||
:param long: Enable long range measurement (default: False)
|
:param long: Enable long range measurement (default: True)
|
||||||
|
|
||||||
:returns: dict. Example:
|
:returns: dict. Example:
|
||||||
|
|
||||||
|
@ -51,40 +86,90 @@ class GpioSensorDistanceVl53L1XPlugin(GpioSensorPlugin):
|
||||||
|
|
||||||
output = {
|
output = {
|
||||||
"short": 83, # Short range measurement in mm
|
"short": 83, # Short range measurement in mm
|
||||||
"medium": 103, # Medium range measurement
|
"medium": 103, # Medium range measurement in mm
|
||||||
"long": 43, # Long range measurement
|
"long": 200, # Long range measurement
|
||||||
}
|
}
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
ret = {}
|
||||||
range_idx = 0
|
range_idx = 0
|
||||||
range_name = None
|
range_name = None
|
||||||
|
range_conf = {
|
||||||
|
'short': short,
|
||||||
|
'medium': medium,
|
||||||
|
'long': long,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, (key, enabled) in enumerate(range_conf.items()):
|
||||||
|
if not enabled:
|
||||||
|
continue
|
||||||
|
|
||||||
for i, r in enumerate(['short', 'medium', 'long']):
|
|
||||||
if eval(r):
|
|
||||||
range_idx = i + 1
|
range_idx = i + 1
|
||||||
range_name = r
|
range_name = key
|
||||||
break
|
|
||||||
|
|
||||||
assert range_name is not None
|
|
||||||
device = self._get_device(ranging=range_idx)
|
|
||||||
ret = {}
|
|
||||||
|
|
||||||
|
with self._get_device(ranging=range_idx) as device:
|
||||||
try:
|
try:
|
||||||
ret[range_name] = device.get_distance()
|
ret[range_name] = device.get_distance()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.exception(e)
|
self.logger.exception(e)
|
||||||
|
self.wait_stop(1)
|
||||||
try:
|
|
||||||
self._device.stop_ranging()
|
|
||||||
self._device.close()
|
|
||||||
except Exception as e:
|
|
||||||
self.logger.warning('Error while closing device: {}'.format(str(e)))
|
|
||||||
|
|
||||||
self._device = None
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
@action
|
||||||
|
def get_data(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
(Deprecated) alias for :meth:`.status`.
|
||||||
|
"""
|
||||||
|
return self.status(*args, **kwargs)
|
||||||
|
|
||||||
|
@action
|
||||||
|
def get_measurement(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
(Deprecated) alias for :meth:`.status`.
|
||||||
|
"""
|
||||||
|
return self.status(*args, **kwargs)
|
||||||
|
|
||||||
|
@override
|
||||||
|
def transform_entities(self, entities: Mapping[str, int]) -> List[Device]:
|
||||||
|
return super().transform_entities( # type: ignore
|
||||||
|
[
|
||||||
|
Device(
|
||||||
|
id='vl53l1x',
|
||||||
|
name='VL53L1X Distance Sensor',
|
||||||
|
children=[
|
||||||
|
DistanceSensor(
|
||||||
|
id=f'vl53l1x:{key}',
|
||||||
|
name=f'{key} distance',
|
||||||
|
value=value,
|
||||||
|
unit='mm',
|
||||||
|
)
|
||||||
|
for key, value in entities.items()
|
||||||
|
],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
@override
|
||||||
|
def publish_entities(self, entities: Mapping[str, int], *_, **__) -> List[Device]:
|
||||||
|
get_bus().post(
|
||||||
|
SensorDataChangeEvent(
|
||||||
|
data=entities,
|
||||||
|
source=get_plugin_name_by_class(self.__class__),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return super().publish_entities(entities) # type: ignore
|
||||||
|
|
||||||
|
@override
|
||||||
|
def main(self):
|
||||||
|
while not self.should_stop():
|
||||||
|
status = self._status()
|
||||||
|
if status != self._last_data:
|
||||||
|
self.publish_entities(status)
|
||||||
|
|
||||||
|
self._last_data = status
|
||||||
|
self.wait_stop(self.poll_interval)
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
manifest:
|
manifest:
|
||||||
events: []
|
events:
|
||||||
|
platypush.message.event.sensor import SensorDataChangeEvent:
|
||||||
|
|
||||||
install:
|
install:
|
||||||
pip:
|
pip:
|
||||||
- smbus2
|
- smbus2
|
||||||
- vl53l1x
|
- vl53l1x
|
||||||
package: platypush.plugins.gpio.sensor.distance.vl53l1x
|
package: platypush.plugins.sensor.distance.vl53l1x
|
||||||
type: plugin
|
type: plugin
|
||||||
|
|
Loading…
Reference in a new issue