Skip to content

Commit 65f5b93

Browse files
committed
v1.2.7
1 parent 04d4c18 commit 65f5b93

File tree

3 files changed

+96
-16
lines changed

3 files changed

+96
-16
lines changed

custom_components/qingping_cgs1/number.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
CONF_UPDATE_INTERVAL, DEFAULT_UPDATE_INTERVAL,
1515
CONF_CO2_OFFSET, CONF_PM25_OFFSET, CONF_PM10_OFFSET,
1616
CONF_NOISE_OFFSET, CONF_TVOC_OFFSET, CONF_TVOC_INDEX_OFFSET,
17-
CONF_POWER_OFF_TIME, CONF_DISPLAY_OFF_TIME, CONF_NIGHT_MODE_START_TIME, CONF_NIGHT_MODE_END_TIME,
17+
CONF_POWER_OFF_TIME,
1818
CONF_AUTO_SLIDING_TIME, CONF_SCREENSAVER_TYPE, CONF_TIMEZONE,
1919
DEFAULT_SENSOR_OFFSET
2020
)
@@ -30,6 +30,10 @@ async def async_setup_entry(
3030
model = config_entry.data[CONF_MODEL]
3131
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
3232
native_temp_unit = hass.config.units.temperature_unit
33+
if native_temp_unit == UnitOfTemperature.FAHRENHEIT:
34+
step = 0.1
35+
else:
36+
step = 1
3337

3438
device_info = {
3539
"identifiers": {(DOMAIN, mac)},
@@ -39,8 +43,8 @@ async def async_setup_entry(
3943
}
4044

4145
entities = [
42-
QingpingCGSxOffsetNumber(coordinator, config_entry, mac, name, "Temp Offset", CONF_TEMPERATURE_OFFSET, device_info, native_temp_unit),
43-
QingpingCGSxOffsetNumber(coordinator, config_entry, mac, name, "Humidity Offset", CONF_HUMIDITY_OFFSET, device_info, "%"),
46+
QingpingCGSxOffsetNumber(coordinator, config_entry, mac, name, "Temp Offset", CONF_TEMPERATURE_OFFSET, device_info, native_temp_unit, step),
47+
QingpingCGSxOffsetNumber(coordinator, config_entry, mac, name, "Humidity Offset", CONF_HUMIDITY_OFFSET, device_info, "%", step),
4448
QingpingCGSxUpdateIntervalNumber(coordinator, config_entry, mac, name, device_info),
4549
QingpingCGSxSensorOffsetNumber(coordinator, config_entry, mac, name, "CO2 Offset", CONF_CO2_OFFSET, device_info, "ppm"),
4650
QingpingCGSxSensorOffsetNumber(coordinator, config_entry, mac, name, "PM2.5 Offset", CONF_PM25_OFFSET, device_info, "µg/m³"),
@@ -62,7 +66,7 @@ async def async_setup_entry(
6266
QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Power Off Time", CONF_POWER_OFF_TIME, device_info, 0, 60, 1, 30, "minutes", NumberMode.SLIDER),
6367
#QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Display Off Time", CONF_DISPLAY_OFF_TIME, device_info, 0, 300, 1, 30, "seconds", NumberMode.SLIDER),
6468
QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Auto Sliding Time", CONF_AUTO_SLIDING_TIME, device_info, 0, 180, 5, 30, "seconds", NumberMode.SLIDER),
65-
QingpingCGSxScreensaverTypeNumber(coordinator, config_entry, mac, name, device_info),
69+
#QingpingCGSxScreensaverTypeNumber(coordinator, config_entry, mac, name, device_info),
6670
QingpingCGSxTimezoneNumber(coordinator, config_entry, mac, name, device_info),
6771
])
6872

@@ -71,7 +75,7 @@ async def async_setup_entry(
7175
class QingpingCGSxOffsetNumber(CoordinatorEntity, NumberEntity):
7276
"""Representation of a Qingping CGSx offset number input."""
7377

74-
def __init__(self, coordinator, config_entry, mac, name, offset_name, offset_key, device_info, unit_of_measurement):
78+
def __init__(self, coordinator, config_entry, mac, name, offset_name, offset_key, device_info, unit_of_measurement, step):
7579
"""Initialize the number entity."""
7680
super().__init__(coordinator)
7781
self._config_entry = config_entry
@@ -82,7 +86,7 @@ def __init__(self, coordinator, config_entry, mac, name, offset_name, offset_key
8286
self._attr_device_info = device_info
8387
self._attr_native_min_value = -10
8488
self._attr_native_max_value = 10
85-
self._attr_native_step = 1
89+
self._attr_native_step = step
8690
self._attr_native_unit_of_measurement = unit_of_measurement
8791
self._attr_entity_category = EntityCategory.CONFIG
8892
self._attr_mode = NumberMode.BOX # Use number box instead of slider

custom_components/qingping_cgs1/select.py

Lines changed: 80 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,27 @@
44
from homeassistant.components.select import SelectEntity
55
from homeassistant.config_entries import ConfigEntry
66
from homeassistant.const import CONF_NAME, CONF_MAC, CONF_MODEL
7-
from homeassistant.core import HomeAssistant
7+
from homeassistant.core import HomeAssistant, callback
88
from homeassistant.helpers.entity_platform import AddEntitiesCallback
99
from homeassistant.helpers.update_coordinator import CoordinatorEntity
1010
from homeassistant.helpers.entity import EntityCategory
1111

12-
from .const import DOMAIN, CONF_TVOC_UNIT, CONF_ETVOC_UNIT
12+
from .const import DOMAIN, CONF_TVOC_UNIT, CONF_ETVOC_UNIT, CONF_SCREENSAVER_TYPE
1313

1414
TVOC_UNIT_OPTIONS = ["ppb", "ppm", "mg/m³"]
1515
ETVOC_UNIT_OPTIONS = ["index", "ppb", "mg/m³"]
1616

17+
# Mapping between display names and values for screensaver types
18+
SCREENSAVER_OPTIONS = {
19+
"All sensors": 0,
20+
"Current sensor": 1,
21+
"Clock and all sensors": 2,
22+
"Clock and current sensor": 3,
23+
}
24+
25+
# Reverse mapping for looking up names from values
26+
SCREENSAVER_VALUES = {v: k for k, v in SCREENSAVER_OPTIONS.items()}
27+
1728
async def async_setup_entry(
1829
hass: HomeAssistant,
1930
config_entry: ConfigEntry,
@@ -32,15 +43,23 @@ async def async_setup_entry(
3243
"model": model,
3344
}
3445

46+
entities = []
47+
3548
if model == "CGS1":
36-
async_add_entities([
37-
QingpingCGSxTVOCUnitSelect(coordinator, config_entry, mac, name, device_info, CONF_TVOC_UNIT, TVOC_UNIT_OPTIONS),
38-
])
49+
entities.append(
50+
QingpingCGSxTVOCUnitSelect(coordinator, config_entry, mac, name, device_info, CONF_TVOC_UNIT, TVOC_UNIT_OPTIONS)
51+
)
3952
elif model == "CGS2":
40-
async_add_entities([
41-
QingpingCGSxTVOCUnitSelect(coordinator, config_entry, mac, name, device_info, CONF_ETVOC_UNIT, ETVOC_UNIT_OPTIONS),
42-
])
43-
# CGDN1 does not have TVOC sensor, so no select entity needed
53+
entities.append(
54+
QingpingCGSxTVOCUnitSelect(coordinator, config_entry, mac, name, device_info, CONF_ETVOC_UNIT, ETVOC_UNIT_OPTIONS)
55+
)
56+
elif model == "CGDN1":
57+
entities.append(
58+
QingpingCGSxScreensaverTypeSelect(coordinator, config_entry, mac, name, device_info)
59+
)
60+
61+
if entities:
62+
async_add_entities(entities)
4463

4564
class QingpingCGSxTVOCUnitSelect(CoordinatorEntity, SelectEntity):
4665
"""Representation of a Qingping CGSx TVOC unit select entity."""
@@ -84,4 +103,56 @@ def _handle_coordinator_update(self) -> None:
84103
"""Handle updated data from the coordinator."""
85104
if CONF_TVOC_UNIT not in self.coordinator.data:
86105
self.coordinator.data[self._conf_unit] = self._config_entry.data.get(self._conf_unit, self._unit_options[0])
106+
self.async_write_ha_state()
107+
108+
class QingpingCGSxScreensaverTypeSelect(CoordinatorEntity, SelectEntity):
109+
"""Representation of a Qingping CGSx screensaver type select input."""
110+
111+
def __init__(self, coordinator, config_entry, mac, name, device_info):
112+
"""Initialize the select entity."""
113+
super().__init__(coordinator)
114+
self._config_entry = config_entry
115+
self._mac = mac
116+
self._attr_name = f"{name} Screensaver Type"
117+
self._attr_unique_id = f"{mac}_screensaver_type"
118+
self._attr_device_info = device_info
119+
self._attr_entity_category = EntityCategory.CONFIG
120+
self._attr_options = list(SCREENSAVER_OPTIONS.keys())
121+
122+
@property
123+
def current_option(self) -> str:
124+
"""Return the current option."""
125+
value = self.coordinator.data.get(CONF_SCREENSAVER_TYPE, 1)
126+
return SCREENSAVER_VALUES.get(value, "Current sensor")
127+
128+
async def async_select_option(self, option: str) -> None:
129+
"""Update the current option."""
130+
value = SCREENSAVER_OPTIONS.get(option)
131+
if value is None:
132+
return
133+
134+
self.coordinator.data[CONF_SCREENSAVER_TYPE] = value
135+
self.async_write_ha_state()
136+
137+
# Update config entry
138+
new_data = dict(self._config_entry.data)
139+
new_data[CONF_SCREENSAVER_TYPE] = value
140+
self.hass.config_entries.async_update_entry(self._config_entry, data=new_data)
141+
142+
await self.coordinator.async_request_refresh()
143+
144+
# Publish setting change to device
145+
from .sensor import publish_setting_change
146+
await publish_setting_change(self.hass, self._mac, CONF_SCREENSAVER_TYPE, int(value))
147+
148+
async def async_added_to_hass(self) -> None:
149+
"""Run when entity about to be added to hass."""
150+
await super().async_added_to_hass()
151+
self._handle_coordinator_update()
152+
153+
@callback
154+
def _handle_coordinator_update(self) -> None:
155+
"""Handle updated data from the coordinator."""
156+
if CONF_SCREENSAVER_TYPE not in self.coordinator.data:
157+
self.coordinator.data[CONF_SCREENSAVER_TYPE] = self._config_entry.data.get(CONF_SCREENSAVER_TYPE, 1)
87158
self.async_write_ha_state()

custom_components/qingping_cgs1/sensor.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,17 @@ async def _update_settings_from_device(hass: HomeAssistant, config_entry: Config
9797
)
9898

9999
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
100+
native_temp_unit = hass.config.units.temperature_unit
101+
if native_temp_unit == UnitOfTemperature.FAHRENHEIT:
102+
unit_based_calc = (CONF_TEMPERATURE_OFFSET, lambda x: round((x / 100) * 9/5, 1))
103+
else:
104+
unit_based_calc = (CONF_TEMPERATURE_OFFSET, lambda x: round(x / 100, 1))
100105
updated = False
101106

102107
# Map device settings to HA entity keys and conversion functions
103108
setting_mappings = {
104109
# Temperature offset: device sends value * 100, we need to divide by 100
105-
"temperature_offset": (CONF_TEMPERATURE_OFFSET, lambda x: round(x / 100, 1)),
110+
"temperature_offset": unit_based_calc,
106111
# Humidity offset: device sends value * 10, we need to divide by 10
107112
"humidity_offset": (CONF_HUMIDITY_OFFSET, lambda x: round(x / 10, 1)),
108113
# Other offsets: direct integer values

0 commit comments

Comments
 (0)