1 """Support for LaCrosse sensor components."""
3 from __future__
import annotations
5 from datetime
import datetime, timedelta
10 from serial
import SerialException
11 import voluptuous
as vol
15 PLATFORM_SCHEMA
as SENSOR_PLATFORM_SCHEMA,
26 EVENT_HOMEASSISTANT_STOP,
38 _LOGGER = logging.getLogger(__name__)
41 CONF_DATARATE =
"datarate"
42 CONF_EXPIRE_AFTER =
"expire_after"
43 CONF_FREQUENCY =
"frequency"
44 CONF_JEELINK_LED =
"led"
45 CONF_TOGGLE_INTERVAL =
"toggle_interval"
46 CONF_TOGGLE_MASK =
"toggle_mask"
48 DEFAULT_DEVICE =
"/dev/ttyUSB0"
50 DEFAULT_EXPIRE_AFTER = 300
52 TYPES = [
"battery",
"humidity",
"temperature"]
54 SENSOR_SCHEMA = vol.Schema(
56 vol.Required(CONF_ID): cv.positive_int,
57 vol.Required(CONF_TYPE): vol.In(TYPES),
58 vol.Optional(CONF_EXPIRE_AFTER): cv.positive_int,
59 vol.Optional(CONF_NAME): cv.string,
63 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
65 vol.Required(CONF_SENSORS): cv.schema_with_slug_keys(SENSOR_SCHEMA),
66 vol.Optional(CONF_BAUD, default=DEFAULT_BAUD): cv.positive_int,
67 vol.Optional(CONF_DATARATE): cv.positive_int,
68 vol.Optional(CONF_DEVICE, default=DEFAULT_DEVICE): cv.string,
69 vol.Optional(CONF_FREQUENCY): cv.positive_int,
70 vol.Optional(CONF_JEELINK_LED): cv.boolean,
71 vol.Optional(CONF_TOGGLE_INTERVAL): cv.positive_int,
72 vol.Optional(CONF_TOGGLE_MASK): cv.positive_int,
80 add_entities: AddEntitiesCallback,
81 discovery_info: DiscoveryInfoType |
None =
None,
83 """Set up the LaCrosse sensors."""
84 usb_device: str = config[CONF_DEVICE]
85 baud: int = config[CONF_BAUD]
86 expire_after: int |
None = config.get(CONF_EXPIRE_AFTER)
88 _LOGGER.debug(
"%s %s", usb_device, baud)
91 lacrosse = pylacrosse.LaCrosse(usb_device, baud)
93 except SerialException
as exc:
94 _LOGGER.warning(
"Unable to open serial port: %s", exc)
97 hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP,
lambda event: lacrosse.close())
99 if CONF_JEELINK_LED
in config:
100 lacrosse.led_mode_state(config.get(CONF_JEELINK_LED))
101 if CONF_FREQUENCY
in config:
102 lacrosse.set_frequency(config.get(CONF_FREQUENCY))
103 if CONF_DATARATE
in config:
104 lacrosse.set_datarate(config.get(CONF_DATARATE))
105 if CONF_TOGGLE_INTERVAL
in config:
106 lacrosse.set_toggle_interval(config.get(CONF_TOGGLE_INTERVAL))
107 if CONF_TOGGLE_MASK
in config:
108 lacrosse.set_toggle_mask(config.get(CONF_TOGGLE_MASK))
110 lacrosse.start_scan()
112 sensors: list[LaCrosseSensor] = []
113 for device, device_config
in config[CONF_SENSORS].items():
114 _LOGGER.debug(
"%s %s", device, device_config)
116 typ: str = device_config[CONF_TYPE]
117 sensor_class = TYPE_CLASSES[typ]
118 name: str = device_config.get(CONF_NAME, device)
121 sensor_class(hass, lacrosse, device, name, expire_after, device_config)
128 """Implementation of a Lacrosse sensor."""
130 _temperature: float |
None =
None
131 _humidity: int |
None =
None
132 _low_battery: bool |
None =
None
133 _new_battery: bool |
None =
None
138 lacrosse: pylacrosse.LaCrosse,
141 expire_after: int |
None,
144 """Initialize the sensor."""
147 ENTITY_ID_FORMAT, device_id, hass=hass
154 lacrosse.register_callback(
160 """Return the state attributes."""
167 self, lacrosse_sensor: pylacrosse.LaCrosseSensor, user_data:
None
169 """Handle a function that is called from pylacrosse with new values."""
190 """Triggered when value is expired."""
196 """Implementation of a Lacrosse temperature sensor."""
198 _attr_device_class = SensorDeviceClass.TEMPERATURE
199 _attr_state_class = SensorStateClass.MEASUREMENT
200 _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
204 """Return the state of the sensor."""
209 """Implementation of a Lacrosse humidity sensor."""
211 _attr_native_unit_of_measurement = PERCENTAGE
212 _attr_state_class = SensorStateClass.MEASUREMENT
213 _attr_device_class = SensorDeviceClass.HUMIDITY
217 """Return the state of the sensor."""
222 """Implementation of a Lacrosse battery sensor."""
226 """Return the state of the sensor."""
235 """Icon to use in the frontend."""
237 return "mdi:battery-unknown"
239 return "mdi:battery-alert"
243 TYPE_CLASSES: dict[str, type[LaCrosseSensor]] = {
244 "temperature": LaCrosseTemperature,
245 "humidity": LaCrosseHumidity,
246 "battery": LaCrosseBattery,
str|None native_value(self)
int|None native_value(self)
None value_is_expired(self, *datetime _)
None _callback_lacrosse(self, pylacrosse.LaCrosseSensor lacrosse_sensor, None user_data)
dict[str, Any] extra_state_attributes(self)
None __init__(self, HomeAssistant hass, pylacrosse.LaCrosse lacrosse, str device_id, str name, int|None expire_after, ConfigType config)
float|None native_value(self)
None async_write_ha_state(self)
def add_entities(account, async_add_entities, tracked)
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
str async_generate_entity_id(str entity_id_format, str|None name, Iterable[str]|None current_ids=None, HomeAssistant|None hass=None)
CALLBACK_TYPE async_track_point_in_utc_time(HomeAssistant hass, HassJob[[datetime], Coroutine[Any, Any, None]|None]|Callable[[datetime], Coroutine[Any, Any, None]|None] action, datetime point_in_time)