Include files

main
Enkhbaatar Tsogtbaatar 6 months ago
parent 72839a82a6
commit 929efdd12c

@ -0,0 +1 @@
"""Solareco sensor integration"""

@ -0,0 +1,9 @@
{
"domain": "solareco",
"name": "solareco",
"version": "1.0.0",
"dependencies": [],
"requirments": [],
"codeowners": [],
"iot_class": "cloud_polling"
}

@ -0,0 +1,138 @@
import logging
import telnetlib
from datetime import timedelta, datetime, time
from typing import Callable, Any
import re
from homeassistant.components.sensor import SensorEntity, SensorStateClass, SensorDeviceClass
from homeassistant.const import UnitOfTemperature, UnitOfPower, UnitOfElectricPotential, UnitOfElectricCurrent, \
UnitOfEnergy, UnitOfFrequency, UnitOfTime
from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.event import async_track_time_interval
SIGNAL = 'solareco'
DOMAIN = 'solareco'
_LOGGER = logging.getLogger('solareco')
class SolarecoSensorConfig:
def __init__(self, name,
unit_of_measurement,
device_class,
data_transformation,
icon,
state_class=SensorStateClass.MEASUREMENT):
self.name = name
self.unit_of_measurement = unit_of_measurement
self.device_class = device_class
self.data_transformation = data_transformation
self.icon = icon
self.state_class = state_class
SENSORS = [
SolarecoSensorConfig('relay', None, None, lambda data: re.findall('AC+\d', data)[0][2:] if re.search('AC+\d',data) else re.findall('R:+\d', data)[0][2:],""),
SolarecoSensorConfig('fan', None, None, lambda data: re.findall('F:+\d', data)[0][2:] if re.search('F:+\d',data) else None,"mdi:fan"),
SolarecoSensorConfig('required_voltage', UnitOfElectricPotential.VOLT, None, lambda data: re.findall('\d+U', data)[0][:-1],"mdi:alpha-v-circle-outline"),
SolarecoSensorConfig('voltage', UnitOfElectricPotential.VOLT, SensorDeviceClass.VOLTAGE, lambda data: re.findall('\d+V', data)[0][:-1],"mdi:alpha-v-circle-outline"),
SolarecoSensorConfig('current', UnitOfElectricCurrent.MILLIAMPERE, SensorDeviceClass.CURRENT, lambda data: re.findall('\d+mA', data)[0][:-2],"mdi:current-dc"),
SolarecoSensorConfig('power', UnitOfPower.WATT, SensorDeviceClass.POWER, lambda data: re.findall('\d+W', data)[0][:-1],"mdi:alpha-w-circle-outline"),
SolarecoSensorConfig('frequency', UnitOfFrequency.HERTZ, SensorDeviceClass.FREQUENCY, lambda data: re.findall('\d+Hz', data)[0][:-2] if re.search('\d+Hz',data) else None,""),
SolarecoSensorConfig('cooler_temperature', UnitOfTemperature.CELSIUS, SensorDeviceClass.TEMPERATURE, lambda data: re.findall('\d+C', data)[0][:-1],""),
SolarecoSensorConfig('boiler_temperature', UnitOfTemperature.CELSIUS, SensorDeviceClass.TEMPERATURE, lambda data: re.findall('(\d+):\d+C',data)[0],""),
SolarecoSensorConfig('pulse_width', UnitOfTime.MICROSECONDS, None, lambda data: re.findall('\d+us', data)[0][:-2],""),
SolarecoSensorConfig('total_energy', UnitOfEnergy.WATT_HOUR, SensorDeviceClass.ENERGY, lambda data: re.findall('\d+kWh\s\d+Wh', data)[0].replace(' ','').replace('kWh','').replace('Wh','') if re.search('\d+kWh\s\d+Wh', data) else None,"mdi:alpha-w-circle-outline"),
SolarecoSensorConfig('day_energy', UnitOfEnergy.WATT_HOUR, SensorDeviceClass.ENERGY, lambda data: re.findall('\d+Wh', data)[0][:-2],"mdi:alpha-w-circle-outline" ,SensorStateClass.TOTAL_INCREASING),
]
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None) -> True:
_LOGGER.info(str(config))
sensor_connector = SensorConnector(hass, config['host'], config['port'])
# Do first update
await hass.async_add_executor_job(sensor_connector.update)
# Poll for updates in the background
async_track_time_interval(
hass,
lambda now: sensor_connector.update(),
timedelta(seconds=int(config['poll_interval_seconds'])),
)
entities: list[SensorEntity] = []
entities.extend([SolarecoSensor(sensor_connector, sensor_config) for sensor_config in SENSORS])
async_add_entities(entities, True)
hass.data.setdefault(DOMAIN, {})
class SolarecoSensor(SensorEntity):
def __init__(self, sensor_connector, sensor_config: SolarecoSensorConfig):
super().__init__()
self.sensor_connector = sensor_connector
self.sensor_config = sensor_config
self._attr_has_entity_name = True
self._attr_translation_key = self.sensor_config.name
self._state = None
self._state_attributes = None
self._attr_icon = self.sensor_config.icon
async def async_added_to_hass(self) -> None:
self.async_on_remove(
async_dispatcher_connect(self.hass, SIGNAL, self._async_update_callback)
)
@callback
def _async_update_callback(self):
self._async_update_data()
self.async_write_ha_state()
@property
def unique_id(self):
return f"{'solareco'} {self.sensor_config.name}"
# @property
# def name(self):
# return f"{'solareco'} {self.sensor_config.name}"
@property
def native_value(self):
return self._state
@property
def state_class(self):
return self.sensor_config.state_class
@property
def device_class(self):
return self.sensor_config.device_class
@property
def native_unit_of_measurement(self):
return self.sensor_config.unit_of_measurement
@callback
def _async_update_data(self):
self._state = self.sensor_connector.data[self.sensor_config.name]
class SensorConnector:
def __init__(self, hass, solareco_host, solareco_port):
self.hass = hass
self.solareco_host = solareco_host
self.solareco_port = solareco_port
self.data = {SENSORS[i]: None for i in range(0, len(SENSORS))}
def update(self):
try:
with telnetlib.Telnet(self.solareco_host, self.solareco_port) as tn:
line = tn.read_until(b'\n').decode('ascii')
for i in range(0, len(SENSORS)):
sensor = SENSORS[i]
self.data[sensor.name] = sensor.data_transformation(line)
dispatcher_send(self.hass, SIGNAL)
except:
_LOGGER.error("Can't connect to SolarEco")

@ -0,0 +1,43 @@
{
"entity": {
"sensor": {
"relay": {
"name": "relay"
},
"fan": {
"name": "fan"
},
"required_voltage": {
"name": "required_voltage"
},
"voltage": {
"name": "voltage"
},
"current": {
"name": "current"
},
"power": {
"name": "power"
},
"frequency": {
"name": "frequency"
},
"cooler_temperature": {
"name": "cooler_temperature"
},
"boiler_temperature": {
"name": "boiler_temperature"
},
"pulse_width": {
"name": "day_energy"
},
"total_energy": {
"name": "total_energy"
},
"day_energy": {
"name": "day_energy"
}
}
}
}

@ -0,0 +1,43 @@
{
"entity": {
"sensor": {
"relay": {
"name": "relé"
},
"fan": {
"name": "větrák"
},
"required_voltage": {
"name": "požadované_napětí"
},
"voltage": {
"name": "napětí"
},
"current": {
"name": "proud"
},
"power": {
"name": "výkon"
},
"frequency": {
"name": "frekvence"
},
"cooler_temperature": {
"name": "teplota_chladiče"
},
"boiler_temperature": {
"name": "teplota_kotle"
},
"pulse_width": {
"name": "šířka_pulzu"
},
"total_energy": {
"name": "celková_energie"
},
"day_energy": {
"name": "denní_energie"
}
}
}
}

@ -0,0 +1,43 @@
{
"entity": {
"sensor": {
"relay": {
"name": "relay"
},
"fan": {
"name": "fan"
},
"required_voltage": {
"name": "required_voltage"
},
"voltage": {
"name": "voltage"
},
"current": {
"name": "current"
},
"power": {
"name": "power"
},
"frequency": {
"name": "frequency"
},
"cooler_temperature": {
"name": "cooler_temperature"
},
"boiler_temperature": {
"name": "boiler_temperature"
},
"pulse_width": {
"name": "day_energy"
},
"total_energy": {
"name": "total_energy"
},
"day_energy": {
"name": "day_energy"
}
}
}
}
Loading…
Cancel
Save