Skip to content

Commit 8c10d3e

Browse files
committed
v1.2.7
Re added display and power off time Added timezone settings for CGDN1 Hopefully fixed issue for CGDN1
1 parent 996f824 commit 8c10d3e

File tree

3 files changed

+66
-49
lines changed

3 files changed

+66
-49
lines changed

custom_components/qingping_cgs1/const.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,5 @@
6666
CONF_NIGHT_MODE_START_TIME = "night_mode_start_time"
6767
CONF_NIGHT_MODE_END_TIME = "night_mode_end_time"
6868
CONF_AUTO_SLIDING_TIME = "auto_slideing_time"
69-
CONF_SCREENSAVER_TYPE = "screensaver_type"
69+
CONF_SCREENSAVER_TYPE = "screensaver_type"
70+
CONF_TIMEZONE = "timezone"

custom_components/qingping_cgs1/number.py

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
CONF_CO2_OFFSET, CONF_PM25_OFFSET, CONF_PM10_OFFSET,
1616
CONF_NOISE_OFFSET, CONF_TVOC_OFFSET, CONF_TVOC_INDEX_OFFSET,
1717
CONF_POWER_OFF_TIME, CONF_DISPLAY_OFF_TIME, CONF_NIGHT_MODE_START_TIME, CONF_NIGHT_MODE_END_TIME,
18-
CONF_AUTO_SLIDING_TIME, CONF_SCREENSAVER_TYPE,
18+
CONF_AUTO_SLIDING_TIME, CONF_SCREENSAVER_TYPE, CONF_TIMEZONE,
1919
DEFAULT_SENSOR_OFFSET
2020
)
2121

@@ -59,10 +59,11 @@ async def async_setup_entry(
5959
])
6060
elif model == "CGDN1":
6161
entities.extend([
62-
#QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Power Off Time", CONF_POWER_OFF_TIME, device_info, 0, 60, 1, 30, "minutes"),
63-
#QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Display Off Time", CONF_DISPLAY_OFF_TIME, device_info, 0, 300, 1, 30, "seconds"),
64-
QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Auto Sliding Time", CONF_AUTO_SLIDING_TIME, device_info, 0, 180, 5, 30, "seconds"),
62+
QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Power Off Time", CONF_POWER_OFF_TIME, device_info, 0, 60, 1, 30, "minutes", NumberMode.SLIDER),
63+
QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Display Off Time", CONF_DISPLAY_OFF_TIME, device_info, 0, 300, 1, 30, "seconds", NumberMode.SLIDER),
64+
QingpingCGSxTimeNumber(coordinator, config_entry, mac, name, "Auto Sliding Time", CONF_AUTO_SLIDING_TIME, device_info, 0, 180, 5, 30, "seconds", NumberMode.SLIDER),
6565
QingpingCGSxScreensaverTypeNumber(coordinator, config_entry, mac, name, device_info),
66+
QingpingCGSxTimezoneNumber(coordinator, config_entry, mac, name, device_info),
6667
])
6768

6869
async_add_entities(entities)
@@ -245,7 +246,7 @@ def _handle_coordinator_update(self) -> None:
245246
class QingpingCGSxTimeNumber(CoordinatorEntity, NumberEntity):
246247
"""Representation of a Qingping CGSx time setting number input."""
247248

248-
def __init__(self, coordinator, config_entry, mac, name, time_name, time_key, device_info, min_val, max_val, step, default_val, unit):
249+
def __init__(self, coordinator, config_entry, mac, name, time_name, time_key, device_info, min_val, max_val, step, default_val, unit, mode=NumberMode.BOX):
249250
"""Initialize the number entity."""
250251
super().__init__(coordinator)
251252
self._config_entry = config_entry
@@ -260,6 +261,7 @@ def __init__(self, coordinator, config_entry, mac, name, time_name, time_key, de
260261
self._attr_native_step = step
261262
self._attr_entity_category = EntityCategory.CONFIG
262263
self._attr_native_unit_of_measurement = unit
264+
self._attr_mode = mode
263265

264266
@property
265267
def native_value(self) -> int:
@@ -342,4 +344,55 @@ def _handle_coordinator_update(self) -> None:
342344
"""Handle updated data from the coordinator."""
343345
if CONF_SCREENSAVER_TYPE not in self.coordinator.data:
344346
self.coordinator.data[CONF_SCREENSAVER_TYPE] = self._config_entry.data.get(CONF_SCREENSAVER_TYPE, 1)
347+
self.async_write_ha_state()
348+
349+
class QingpingCGSxTimezoneNumber(CoordinatorEntity, NumberEntity):
350+
"""Representation of a Qingping CGSx timezone setting number input."""
351+
352+
def __init__(self, coordinator, config_entry, mac, name, device_info):
353+
"""Initialize the number entity."""
354+
super().__init__(coordinator)
355+
self._config_entry = config_entry
356+
self._mac = mac
357+
self._attr_name = f"{name} Time Zone"
358+
self._attr_unique_id = f"{mac}_timezone"
359+
self._attr_device_info = device_info
360+
self._attr_native_min_value = -12
361+
self._attr_native_max_value = 14
362+
self._attr_native_step = 0.5
363+
self._attr_entity_category = EntityCategory.CONFIG
364+
self._attr_mode = NumberMode.BOX
365+
366+
@property
367+
def native_value(self) -> float:
368+
"""Return the current value."""
369+
return self.coordinator.data.get(CONF_TIMEZONE, 0)
370+
371+
async def async_set_native_value(self, value: float) -> None:
372+
"""Update the current value."""
373+
self.coordinator.data[CONF_TIMEZONE] = value
374+
self.async_write_ha_state()
375+
376+
# Update config entry
377+
new_data = dict(self._config_entry.data)
378+
new_data[CONF_TIMEZONE] = value
379+
self.hass.config_entries.async_update_entry(self._config_entry, data=new_data)
380+
381+
await self.coordinator.async_request_refresh()
382+
383+
# Publish setting change to device (value * 10 for device)
384+
from .sensor import publish_setting_change
385+
device_value = int(value * 10)
386+
await publish_setting_change(self.hass, self._mac, CONF_TIMEZONE, device_value)
387+
388+
async def async_added_to_hass(self) -> None:
389+
"""Run when entity about to be added to hass."""
390+
await super().async_added_to_hass()
391+
self._handle_coordinator_update()
392+
393+
@callback
394+
def _handle_coordinator_update(self) -> None:
395+
"""Handle updated data from the coordinator."""
396+
if CONF_TIMEZONE not in self.coordinator.data:
397+
self.coordinator.data[CONF_TIMEZONE] = self._config_entry.data.get(CONF_TIMEZONE, 0)
345398
self.async_write_ha_state()

custom_components/qingping_cgs1/sensor.py

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,7 @@ async def async_update_data():
219219
def message_received(message):
220220
"""Handle new MQTT messages."""
221221
try:
222-
_LOGGER.warning("=== MQTT MESSAGE RECEIVED === Topic: %s", message.topic)
223-
224222
payload = json.loads(message.payload)
225-
_LOGGER.warning("Payload type: %s", type(payload))
226223

227224
if not isinstance(payload, dict):
228225
_LOGGER.error("Payload is not a dictionary")
@@ -235,15 +232,13 @@ def message_received(message):
235232
received_mac = payload.get("mac", "").replace(":", "").upper()
236233
expected_mac = mac.replace(":", "").upper()
237234

238-
_LOGGER.warning("Received MAC: %s, Expected MAC: %s, Type: %s", received_mac, expected_mac, message_type)
239-
240-
# Skip MAC check for type 28 (settings) messages as they don't include MAC
235+
# Skip MAC check for messages without MAC (type 28, 13, 10, 17, etc.)
241236
# We're subscribed to this device's specific topic, so we know it's for us
242237
if received_mac and received_mac != expected_mac:
243238
_LOGGER.debug("Received message for a different device. Expected: %s, Got: %s", expected_mac, received_mac)
244239
return
245240

246-
_LOGGER.warning("Processing MQTT message for device %s", mac)
241+
_LOGGER.debug("Processing MQTT message type %s for device %s", message_type, mac)
247242

248243
# Update timestamp first - any message from device means it's online
249244
# Always use current system time, not device's timestamp which may be unreliable
@@ -267,18 +262,13 @@ def message_received(message):
267262
mac_sensor.update_mac(mac_address)
268263

269264
# Handle type 28 messages (device settings update) - Check BEFORE sensorData
270-
_LOGGER.warning("=== MESSAGE TYPE: %s ===", message_type)
271-
272265
if message_type == 28 or message_type == "28":
273-
_LOGGER.error("!!! TYPE 28 SETTINGS UPDATE DETECTED !!!")
274-
_LOGGER.error("Full payload: %s", json.dumps(payload, indent=2))
266+
_LOGGER.info("Type 28 settings update received for device %s", mac)
275267
settings = payload.get("setting", {})
276-
_LOGGER.error("Settings extracted: %s", settings)
277268
if settings:
278-
_LOGGER.error("!!! CREATING TASK TO UPDATE SETTINGS !!!")
279269
hass.async_create_task(_update_settings_from_device(hass, config_entry, settings, model))
280270
else:
281-
_LOGGER.error("!!! TYPE 28 HAS NO SETTINGS DICT !!!")
271+
_LOGGER.warning("Type 28 message has no settings dict")
282272
return # Don't process as sensor data
283273

284274
sensor_data = payload.get("sensorData")
@@ -336,34 +326,7 @@ def message_received(message):
336326
await mqtt.async_subscribe(
337327
hass, f"{MQTT_TOPIC_PREFIX}/{mac}/up", message_received, 1
338328
)
339-
_LOGGER.warning("=== SUBSCRIBED TO: %s/%s/up ===", MQTT_TOPIC_PREFIX, mac)
340-
341-
# CGDN1-specific: Subscribe to any message for this device to detect when it comes online
342-
# CGDN1 doesn't always send full sensor data on power-on like CGS1/CGS2
343-
if model == "CGDN1":
344-
@callback
345-
def device_alive_check(message):
346-
"""Detect any MQTT activity from CGDN1 device."""
347-
try:
348-
# Skip the main /up topic as it's already handled
349-
if message.topic.endswith("/up"):
350-
return
351-
352-
_LOGGER.debug("CGDN1 device activity detected on topic: %s", message.topic)
353-
# Any MQTT activity from this device means it's alive
354-
if status_sensor.hass:
355-
current_time = int(time.time())
356-
if status_sensor._last_timestamp == 0 or (current_time - status_sensor._last_timestamp) > 60:
357-
_LOGGER.info("CGDN1 device %s appears to be online, updating status", mac)
358-
status_sensor.update_timestamp(current_time)
359-
# Trigger a config publish to get fresh data
360-
asyncio.create_task(sensors[5].publish_config())
361-
except Exception as e:
362-
_LOGGER.error("Error in CGDN1 device alive check: %s", str(e))
363-
364-
await mqtt.async_subscribe(
365-
hass, f"{MQTT_TOPIC_PREFIX}/{mac}/#", device_alive_check, 1
366-
)
329+
_LOGGER.info("Subscribed to MQTT topic: %s/%s/up", MQTT_TOPIC_PREFIX, mac)
367330

368331
# Set up timer for periodic publishing
369332
async def publish_config_wrapper(*args):
@@ -720,4 +683,4 @@ async def async_will_remove_from_hass(self) -> None:
720683
remove_timer = self.hass.data[DOMAIN][self._config_entry.entry_id].get("remove_timer")
721684
if remove_timer:
722685
remove_timer()
723-
await super().async_will_remove_from_hass()
686+
await super().async_will_remove_from_hass()

0 commit comments

Comments
 (0)