From cb771ce608fb8852a26c00c90af0ffda3b7dbd9e Mon Sep 17 00:00:00 2001 From: Ricc68 Date: Tue, 6 May 2025 20:31:13 +0200 Subject: [PATCH 1/4] feat: add a danger icon to OTA page for battery devices when battery is too low to run an update --- src/components/ota-page/index.tsx | 2 + .../power-source/powerSourceOTA.tsx | 56 +++++++++++++++++++ src/i18n/locales/en.json | 1 + ws-messages/onConnect.json | 44 +++++++++++---- 4 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 src/components/power-source/powerSourceOTA.tsx diff --git a/src/components/ota-page/index.tsx b/src/components/ota-page/index.tsx index e8aa56768..34c6a20df 100644 --- a/src/components/ota-page/index.tsx +++ b/src/components/ota-page/index.tsx @@ -13,6 +13,7 @@ import { ModelLink, OTALink, VendorLink } from '../vendor-links/vendor-links'; import { useTranslation, WithTranslation, withTranslation } from 'react-i18next'; import { Column } from 'react-table'; import { Table } from '../grid/ReactTableCom'; +import PowerSourceOTA from '../power-source/powerSourceOTA'; import cx from 'classnames'; type OtaRowProps = { @@ -59,6 +60,7 @@ const StateCell: FunctionComponent = (props) => { > + ); case 'scheduled': diff --git a/src/components/power-source/powerSourceOTA.tsx b/src/components/power-source/powerSourceOTA.tsx new file mode 100644 index 000000000..60023cae3 --- /dev/null +++ b/src/components/power-source/powerSourceOTA.tsx @@ -0,0 +1,56 @@ +import React, { Fragment, FunctionComponent } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Device, DeviceState } from '../../types'; +import style from './style.module.css'; +import { powerSourceTypeToTranslationKey } from './powerSourceTypeToTranslationKey'; +import type { PowerSource } from '../../types'; + +interface PowerSourceOTAProps { + device?: Device; + deviceState?: DeviceState; +} + +const PowerSourceOTA: FunctionComponent = ({ device, deviceState, ...rest }) => { + const { t } = useTranslation('ota'); + let source: PowerSource | undefined = undefined; + + if (device !== undefined) { + source = device.power_source; + } + + if (source !== 'Battery') { + return null; + } + + let batteryPercent: number | undefined = undefined; + let batteryState: string | undefined = undefined; + let batteryLow: boolean | undefined = undefined; + + if (deviceState !== undefined) { + if (deviceState?.battery !== undefined) { + batteryPercent = deviceState.battery as number; + } + if (deviceState?.battery_state !== undefined) { + batteryState = deviceState.battery_state as string; + } + if (deviceState?.battery_low !== undefined) { + batteryLow = deviceState.battery_low as boolean; + } + } + + // Some devices do not use the standardized feature `battery` to report power level. + if ((batteryPercent !== undefined && batteryPercent <= 50) || + (batteryState !== undefined && batteryState === 'low') || + (batteryLow !== undefined && batteryLow === true)) { + return ( + + + + ); + } +}; + +export default PowerSourceOTA; diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 299278727..377a7ad71 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -2577,6 +2577,7 @@ "touchlink": "Touchlink" }, "ota": { + "battery_low_upd": "The firmware update may fail if the batteries are not replaced", "check": "Check for new updates", "check_all": "Check all", "empty_ota_message": "You don't have any devices that support OTA", diff --git a/ws-messages/onConnect.json b/ws-messages/onConnect.json index 15469e2e5..0d7d26eec 100644 --- a/ws-messages/onConnect.json +++ b/ws-messages/onConnect.json @@ -1407,7 +1407,7 @@ }, "friendly_name": "0xbc33acfffe17628b", "ieee_address": "0xbc33acfffe17628b", - "interview_state": "FAILED", + "interview_state": "SUCCESSFUL", "manufacturer": "IKEA of Sweden", "model_id": "TRADFRI on/off switch", "network_address": 25249, @@ -2010,7 +2010,7 @@ "value_on": true } ], - "supports_ota": false, + "supports_ota": true, "vendor": "Xiaomi" }, "endpoints": { @@ -2327,7 +2327,7 @@ "type": "numeric" } ], - "supports_ota": false, + "supports_ota": true, "vendor": "Xiaomi" }, "endpoints": { @@ -2596,7 +2596,7 @@ "type": "numeric" } ], - "supports_ota": false, + "supports_ota": true, "vendor": "Xiaomi" }, "endpoints": { @@ -8652,7 +8652,7 @@ "topic": "bridge/extensions" }, { - "payload": "offline", + "payload": "online", "topic": "0xbc33acfffe17628b/availability" }, { @@ -8707,7 +8707,13 @@ }, { "payload": { - "last_seen": "2022-04-15T16:33:53+08:00" + "battery": 45, + "last_seen": "2022-04-15T16:33:53+08:00", + "update": { + "installed_version": 65552, + "latest_version": 16777233, + "state": "available" + } }, "topic": "0xbc33acfffe17628b" }, @@ -8748,7 +8754,12 @@ "battery": 100, "last_seen": "2022-05-16T20:46:44+08:00", "linkquality": 66, - "voltage": 3042 + "voltage": 3042, + "update": { + "installed_version": 65552, + "latest_version": 16777233, + "state": "available" + } }, "topic": "0x00158d000224154d" }, @@ -8780,12 +8791,17 @@ }, { "payload": { - "battery": 100, + "battery": 65, "humidity": 65.59, "last_seen": "2022-05-16T20:37:54+08:00", "linkquality": 90, "temperature": 25.84, - "voltage": 3035 + "voltage": 3035, + "update": { + "installed_version": 65552, + "latest_version": 16777233, + "state": "available" + } }, "topic": "livingroom/temp_humidity" }, @@ -8811,13 +8827,19 @@ }, { "payload": { - "battery": 0, + "battery": 5, "humidity": 59.96, "last_seen": "2022-05-16T21:06:04+08:00", + "state": "ON", "linkquality": 12, "pressure": 1009.8, "temperature": 32.9, - "voltage": 2815 + "voltage": 2815, + "update": { + "installed_version": 65552, + "latest_version": 16777233, + "state": "available" + } }, "topic": "0x00158d0004866f11" }, From b0affe4b7e4d63649f433c37cef17ea32596d632 Mon Sep 17 00:00:00 2001 From: Ricc68 Date: Tue, 6 May 2025 20:52:37 +0200 Subject: [PATCH 2/4] style: run pretty --- src/components/power-source/powerSourceOTA.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/power-source/powerSourceOTA.tsx b/src/components/power-source/powerSourceOTA.tsx index 60023cae3..bc7800d4e 100644 --- a/src/components/power-source/powerSourceOTA.tsx +++ b/src/components/power-source/powerSourceOTA.tsx @@ -39,15 +39,14 @@ const PowerSourceOTA: FunctionComponent = ({ device, device } // Some devices do not use the standardized feature `battery` to report power level. - if ((batteryPercent !== undefined && batteryPercent <= 50) || + if ( + (batteryPercent !== undefined && batteryPercent <= 50) || (batteryState !== undefined && batteryState === 'low') || - (batteryLow !== undefined && batteryLow === true)) { + (batteryLow !== undefined && batteryLow === true) + ) { return ( - + ); } From 65ad564c52610943521c0010f612a93a666676be Mon Sep 17 00:00:00 2001 From: Ricc68 Date: Sat, 10 May 2025 12:59:40 +0200 Subject: [PATCH 3/4] fix: replace red circle danger icon with yellow triangle warning one --- src/components/power-source/powerSourceOTA.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/power-source/powerSourceOTA.tsx b/src/components/power-source/powerSourceOTA.tsx index bc7800d4e..9bcae1db3 100644 --- a/src/components/power-source/powerSourceOTA.tsx +++ b/src/components/power-source/powerSourceOTA.tsx @@ -2,7 +2,6 @@ import React, { Fragment, FunctionComponent } from 'react'; import { useTranslation } from 'react-i18next'; import { Device, DeviceState } from '../../types'; import style from './style.module.css'; -import { powerSourceTypeToTranslationKey } from './powerSourceTypeToTranslationKey'; import type { PowerSource } from '../../types'; interface PowerSourceOTAProps { @@ -46,7 +45,7 @@ const PowerSourceOTA: FunctionComponent = ({ device, device ) { return ( - + ); } From 0cf3c099c0f28230943e078401ed23ad940309d8 Mon Sep 17 00:00:00 2001 From: Ricc68 Date: Sat, 7 Jun 2025 11:11:48 +0200 Subject: [PATCH 4/4] fix: when OTA file version is negative number return N/A --- src/components/ota-page/index.tsx | 5 +++-- ws-messages/onConnect.json | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/ota-page/index.tsx b/src/components/ota-page/index.tsx index 34c6a20df..ac531eb02 100644 --- a/src/components/ota-page/index.tsx +++ b/src/components/ota-page/index.tsx @@ -189,7 +189,7 @@ class OtaPage extends Component accessor: ({ state }) => { const installed_version = ((state?.update ?? {}) as OTAState).installed_version; - if (typeof installed_version === 'number' && installed_version) + if (typeof installed_version === 'number' && installed_version >= 0) return fileVersion2String(installed_version); else return t('zigbee:firmware_installed_version_na'); }, @@ -199,7 +199,8 @@ class OtaPage extends Component accessor: ({ state }) => { const latest_version = ((state?.update ?? {}) as OTAState).latest_version; - if (typeof latest_version === 'number' && latest_version) return fileVersion2String(latest_version); + if (typeof latest_version === 'number' && latest_version >= 0) + return fileVersion2String(latest_version); else return 'N/A'; }, }, diff --git a/ws-messages/onConnect.json b/ws-messages/onConnect.json index 0d7d26eec..bab71c058 100644 --- a/ws-messages/onConnect.json +++ b/ws-messages/onConnect.json @@ -8694,7 +8694,7 @@ "topic": "dining room/ac power/availability" }, { - "payload": "offline", + "payload": "online", "topic": "0x0017880103d55d65/availability" }, { @@ -8858,7 +8858,12 @@ "brightness": 110, "color_mode": "xy", "last_seen": "2022-04-15T17:48:30+08:00", - "state": "ON" + "state": "ON", + "update": { + "installed_version": -1, + "latest_version": -1, + "state": "unknown" + } }, "topic": "0x0017880103d55d65" }