Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
11cb7ed
add cloud discovery metadata
Terdious Feb 11, 2026
db22529
add local discovery metadata
Terdious Feb 11, 2026
ff5d001
Corrige les URL de l'API locale et du WebSocket pour utiliser localhost
Terdious Feb 11, 2026
ab28de0
feat: enhance Tuya device support with air conditioning and power met…
Terdious Feb 15, 2026
d9598ca
refactor: remove air conditioning model and related mappings; simplif…
Terdious Feb 15, 2026
3612b9c
feat: add local polling and scanning tests for TuyaHandler
Terdious Feb 15, 2026
7ea3468
refactor: simplifier la logique de poll local et améliorer la lisibil…
Terdious Feb 15, 2026
e2d7189
refactor: améliorer la logique de chargement des appareils Tuya et me…
Terdious Feb 15, 2026
5f2d2a5
fix: corriger la logique de pagination dans loadDevices et ajouter un…
Terdious Feb 15, 2026
ebd3dc3
refactor: améliorer la logique de mise à jour des appareils découvert…
Terdious Feb 15, 2026
a3f8359
feat: ajouter des descriptions et des limitations pour la configurati…
Terdious Feb 15, 2026
50e1122
feat: ajouter les champs Product ID et Product Key dans la configurat…
Terdious Feb 15, 2026
513e2d0
refactor: améliorer la journalisation dans le processus de scan local…
Terdious Feb 16, 2026
389d231
logger
Terdious Feb 16, 2026
36dfd91
refactor: améliorer la gestion des erreurs du socket UDP dans le scan…
Terdious Feb 16, 2026
b8e1a9f
refactor: mettre à jour la méthode de liaison des sockets pour permet…
Terdious Feb 16, 2026
8d2536f
feat: améliorer le scan local des appareils Tuya avec gestion des err…
Terdious Feb 16, 2026
a0243b6
feat: mettre à jour les descriptions de configuration Tuya pour inclu…
Terdious Feb 16, 2026
70c7d4a
feat: ajouter des messages d'information sur le protocole 3.5 et la c…
Terdious Feb 17, 2026
3fd0232
feat(tuya): enhance Tuya integration with connection status and manua…
Terdious Feb 20, 2026
8082994
Merge branch 'master' into tuya-local-baseline
Terdious Feb 20, 2026
588225e
feat(tuya): améliorer les tests pour la gestion des connexions et des…
Terdious Feb 20, 2026
924e098
Merge branch 'master' into tuya-local-baseline
Terdious Feb 20, 2026
cc0010e
feat(tuya): enhance device discovery and local polling
Terdious Feb 20, 2026
b6cb28b
feat(tuya): améliorer la gestion des informations locales des apparei…
Terdious Feb 21, 2026
52a54b2
feat(tuya): traduire les clés de produit et améliorer les messages de…
Terdious Feb 21, 2026
ae8a1d6
feat(tuya): améliorer la gestion des erreurs et des messages de débog…
Terdious Feb 21, 2026
c68075d
feat(tuya): nettoyer les messages de débogage et améliorer la gestion…
Terdious Feb 21, 2026
b2ee166
Merge branch 'master' into tuya-local-baseline
Terdious Feb 25, 2026
c5edbbc
ci: rerun
Terdious Feb 25, 2026
c65e264
feat(tuya): ajouter le support de l'UID du compte d'application Tuya,…
Terdious Feb 21, 2026
1f07038
feat(tuya): améliorer la gestion de la configuration Tuya en ajoutant…
Terdious Feb 21, 2026
021176d
feat(tuya): optimiser la récupération des paramètres Tuya en utilisan…
Terdious Feb 21, 2026
01700bb
feat(tuya): finalize v2 local baseline ux and local discovery updates
Terdious Feb 26, 2026
3c0de0c
test(tuya): avoid unhandled rejection warning in local poll timeout
Terdious Feb 26, 2026
92a913f
refactor(tuya): normalize booleans and stabilize base conversions
Terdious Feb 27, 2026
906e124
Merge branch 'master' into tuya-local-baseline
Terdious Feb 27, 2026
1d1fda4
feat(tuya): add local protocol 3.5 support with newgen api
Terdious Feb 26, 2026
e3b95f0
fix(tuya): resolve prefer-const in local scan parser
Terdious Feb 26, 2026
74b081e
chore(tuya): remove obsolete protocol 3.5 unsupported i18n keys
Terdious Feb 26, 2026
50ac347
codecov: rerun
Terdious Feb 27, 2026
0a9f835
feat(tuya): add mapping core for cloud/local smart socket support
Terdious Feb 27, 2026
f82cc73
fix: prettier
Terdious Feb 27, 2026
29b7723
test(tuya): cover local scan branch when parsers fail
Terdious Feb 27, 2026
27152bc
test(tuya): improve mapping and poll branch coverage
Terdious Feb 27, 2026
d8fab71
feat(tuya): restore GitHub issue reporting flow in discover
Terdious Feb 27, 2026
e66e53c
style(tuya): format TuyaDeviceBox with project prettier
Terdious Feb 27, 2026
c49d6e9
fix(tuya): harden init reconnect flag and thing model parsing
Terdious Feb 27, 2026
546b901
fix(tuya): avoid stale state reads in setup save flow
Terdious Feb 27, 2026
b67b2a8
chore(front): apply prettier formatting on tuya setup tab
Terdious Feb 27, 2026
515c9a9
test(tuya): prefer await style in local poll timeout test
Terdious Feb 27, 2026
d4a747c
fix(tuya): align mapping-core with baseline/protocol hardening
Terdious Feb 27, 2026
a57fc3c
chore(front): apply prettier formatting on tuya setup tab
Terdious Feb 27, 2026
a81f8ad
fix(tuya): harden setup state updates and fix disconnect log typo
Terdious Feb 27, 2026
de85694
fix(tuya): harden mapping-core poll and specification extraction
Terdious Feb 27, 2026
6a5eb55
fix(tuya): harden mapping core for thing model fallback and scaled va…
Terdious Feb 28, 2026
2a77646
test(tuya): cover generic mapping core guards
Terdious Feb 28, 2026
3b22df1
feat(tuya): add smart meter support and fixture-based tests
Terdious Feb 28, 2026
8d6792a
style(tuya): fix smart meter fixture lint and formatting
Terdious Feb 28, 2026
f2c785c
fix(tuya): avoid stale device state in local poll
Terdious Feb 28, 2026
53d9f8b
fix(tuya): align feature code parsing and test labels
Terdious Feb 28, 2026
cdfe22c
fix(tuya): move setup side effects to componentDidMount
Terdious Feb 28, 2026
8f2657a
fix(tuya): surface setup variable fetch failures
Terdious Feb 28, 2026
129aa4b
fix(tuya): harden type detection and poll handling
Terdious Feb 28, 2026
8d393ec
test(tuya): align fixture branch regression coverage
Terdious Feb 28, 2026
9863511
fix(tuya): harden poll readers and regression tests
Terdious Mar 1, 2026
94d96ce
fix(tuya): preserve latest params after local poll
Terdious Mar 1, 2026
ec26853
fix(tuya): harden baseline setup and cloud loading
Terdious Mar 1, 2026
c55a6e1
fix(tuya): improve setup alerts and baseline test isolation
Terdious Mar 1, 2026
74138b5
fix(tuya): sanitize local timeouts and persist local-only devices
Terdious Mar 1, 2026
47130ac
fix(tuya): harden mapping normalization and poll fallback
Terdious Mar 1, 2026
ae8b01b
fix(tuya): harden fixture tests and device diagnostics
Terdious Mar 1, 2026
b88e723
style(tuya): apply frontend formatting on device box
Terdious Mar 1, 2026
dc58f5c
fix(tuya): open github issue popup before async check
Terdious Mar 1, 2026
fd11ac1
fix(tuya): harden setup status and local scan follow-up
Terdious Mar 1, 2026
d4479c5
fix(tuya): apply follow-up hardening adjustments
Terdious Mar 1, 2026
fa06ada
feat(tuya): improve unsupported device issue reports
Terdious Mar 1, 2026
33d861e
fix(tuya): refine unsupported cloud code detection
Terdious Mar 1, 2026
b226e5d
refactor(tuya): align frontend boolean helper imports
Terdious Mar 1, 2026
754dd35
docs(tuya): clarify unsupported device onboarding guidance
Terdious Mar 1, 2026
85f643c
test(tuya): align smart meter fixtures with issue captures
Terdious Mar 1, 2026
359fdd7
docs(tuya): improve unsupported device guidance
Terdious Mar 1, 2026
124b341
Add support for LSC Power Plug FR smart socket
Terdious Mar 2, 2026
b2cc02d
Fix Tuya loadDeviceDetails null-report test
Terdious Mar 2, 2026
b483099
Refine Tuya smart socket ignored mappings
Terdious Mar 2, 2026
3171274
test(tuya): harden local scan and cloud loading cases
Terdious Mar 2, 2026
2ca5a62
feat(tuya): support cloud shadow reads for thing-model devices
Terdious Mar 3, 2026
2b359f1
feat(tuya): add support for pilot thermostat devices
Terdious Mar 3, 2026
b6ce656
test(tuya): align LSC smart socket fixture cloud strategy
Terdious Mar 3, 2026
bd0d9ba
test(tuya): restore unified cloud strategy fixture on thermostat branch
Terdious Mar 3, 2026
340353a
fix(tuya): handle unreachable local devices cleanly
Terdious Mar 3, 2026
df476d3
test(tuya): improve thermostat branch coverage
Terdious Mar 3, 2026
33241a1
refactor(tuya): simplify poll temperature guards
Terdious Mar 3, 2026
034de26
refactor(tuya): remove dead defensive guards
Terdious Mar 4, 2026
a66f773
feat(tuya): add air-conditioner mappings and controls
Terdious Mar 5, 2026
a3ae938
chore(tuya): clarify cloud setValue logs
Terdious Mar 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions front/src/components/boxs/device-in-room/DeviceRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import NumberDeviceFeature from './device-features/NumberDeviceFeature';
import CoverDeviceFeature from './device-features/CoverDeviceFeature';
import SetpointDeviceFeature from './device-features/SetpointDeviceFeature';
import AirConditioningModeDeviceFeature from './device-features/AirConditioningModeDeviceFeature';
import AirConditioningFanSpeedDeviceFeature from './device-features/AirConditioningFanSpeedDeviceFeature';
import AirConditioningSwingDeviceFeature from './device-features/AirConditioningSwingDeviceFeature';
import PilotWireModeDeviceFeature from './device-features/PilotWireModeDeviceFeature';
import LMHVolumeDeviceFeature from './device-features/LMHVolumeDeviceFeature';
import PushDeviceFeature from './device-features/PushDeviceFeature';
Expand All @@ -31,6 +33,9 @@ const ROW_TYPE_BY_FEATURE_TYPE = {
[DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE]: SetpointDeviceFeature,
[DEVICE_FEATURE_TYPES.AIR_CONDITIONING.MODE]: AirConditioningModeDeviceFeature,
[DEVICE_FEATURE_TYPES.AIR_CONDITIONING.TARGET_TEMPERATURE]: SetpointDeviceFeature,
[DEVICE_FEATURE_TYPES.AIR_CONDITIONING.FAN_SPEED]: AirConditioningFanSpeedDeviceFeature,
[DEVICE_FEATURE_TYPES.AIR_CONDITIONING.SWING_HORIZONTAL]: AirConditioningSwingDeviceFeature,
[DEVICE_FEATURE_TYPES.AIR_CONDITIONING.SWING_VERTICAL]: AirConditioningSwingDeviceFeature,
[DEVICE_FEATURE_TYPES.HEATER.PILOT_WIRE_MODE]: PilotWireModeDeviceFeature,
[DEVICE_FEATURE_TYPES.LOCK.BINARY]: BinaryDeviceFeature,
[DEVICE_FEATURE_TYPES.SIREN.LMH_VOLUME]: LMHVolumeDeviceFeature,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ const SUPPORTED_FEATURE_TYPES = [
DEVICE_FEATURE_TYPES.THERMOSTAT.TARGET_TEMPERATURE,
DEVICE_FEATURE_TYPES.AIR_CONDITIONING.MODE,
DEVICE_FEATURE_TYPES.AIR_CONDITIONING.TARGET_TEMPERATURE,
DEVICE_FEATURE_TYPES.AIR_CONDITIONING.FAN_SPEED,
DEVICE_FEATURE_TYPES.AIR_CONDITIONING.SWING_HORIZONTAL,
DEVICE_FEATURE_TYPES.AIR_CONDITIONING.SWING_VERTICAL,
DEVICE_FEATURE_TYPES.LOCK.BINARY,
DEVICE_FEATURE_TYPES.LOCK.STATE,
DEVICE_FEATURE_TYPES.HEATER.PILOT_WIRE_MODE,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import get from 'get-value';
import { Text } from 'preact-i18n';

import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts';
import { AC_FAN_SPEED } from '../../../../../../server/utils/constants';

const FAN_SPEED_OPTIONS = [
{ value: AC_FAN_SPEED.AUTO, i18nKey: 'auto' },
{ value: AC_FAN_SPEED.LOW, i18nKey: 'low' },
{ value: AC_FAN_SPEED.LOW_MID, i18nKey: 'low-mid' },
{ value: AC_FAN_SPEED.MID, i18nKey: 'mid' },
{ value: AC_FAN_SPEED.MID_HIGH, i18nKey: 'mid-high' },
{ value: AC_FAN_SPEED.HIGH, i18nKey: 'high' },
{ value: AC_FAN_SPEED.MUTE, i18nKey: 'mute' },
{ value: AC_FAN_SPEED.TURBO, i18nKey: 'turbo' }
];

const AirConditioningFanSpeedDeviceFeature = props => {
const { deviceFeature } = props;
const { category, type } = deviceFeature;
const rawValue = deviceFeature.last_value;
const lastValue = rawValue != null && !Number.isNaN(Number(rawValue)) ? Number(rawValue) : rawValue;

const updateValue = e => {
props.updateValueWithDebounce(deviceFeature, Number(e.currentTarget.value));
};

return (
<tr>
<td>
<i class={`fe fe-${get(DeviceFeatureCategoriesIcon, `${category}.${type}`, { default: 'wind' })}`} />
</td>
<td>{props.rowName}</td>

<td class="py-0">
<div class="justify-content-end">
<div class="form-group mb-0">
<select value={lastValue} onChange={updateValue} class="form-control form-control-sm">
{FAN_SPEED_OPTIONS.map(option => (
<option value={option.value} key={option.value}>
<Text id={`deviceFeatureAction.category.${category}.${type}.${option.i18nKey}`} />
</option>
))}
</select>
</div>
</div>
</td>
</tr>
);
};

export default AirConditioningFanSpeedDeviceFeature;
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
import get from 'get-value';
import { Text } from 'preact-i18n';
import cx from 'classnames';

import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts';
import { AC_MODE } from '../../../../../../server/utils/constants';

const AirConditioningModeDeviceFeature = ({ children, ...props }) => {
const { deviceFeature } = props;
const { category, type, last_value: lastValue } = deviceFeature;

function updateValue(value) {
props.updateValueWithDebounce(deviceFeature, value);
}
const MODE_OPTIONS = [
{ value: AC_MODE.AUTO, i18nKey: 'auto' },
{ value: AC_MODE.COOLING, i18nKey: 'cooling' },
{ value: AC_MODE.HEATING, i18nKey: 'heating' },
{ value: AC_MODE.DRYING, i18nKey: 'drying' },
{ value: AC_MODE.FAN, i18nKey: 'fan' }
];

function auto() {
updateValue(AC_MODE.AUTO);
}

function cooling() {
updateValue(AC_MODE.COOLING);
}
const AirConditioningModeDeviceFeature = props => {
const { deviceFeature } = props;
const { category, type } = deviceFeature;
const rawValue = deviceFeature.last_value;
const lastValue = rawValue != null && !Number.isNaN(Number(rawValue)) ? Number(rawValue) : rawValue;

function heating() {
updateValue(AC_MODE.HEATING);
}
const updateValue = e => {
props.updateValueWithDebounce(deviceFeature, Number(e.currentTarget.value));
};

return (
<tr>
Expand All @@ -33,32 +30,15 @@ const AirConditioningModeDeviceFeature = ({ children, ...props }) => {
<td>{props.rowName}</td>

<td class="py-0">
<div class="d-flex justify-content-end">
<div class="btn-group" role="group">
<button
class={cx('btn btn-sm btn-secondary', {
active: lastValue === AC_MODE.AUTO
})}
onClick={auto}
>
<Text id={`deviceFeatureAction.category.${category}.${type}.auto`} plural={AC_MODE.HEATING} />
</button>
<button
class={cx('btn btn-sm btn-secondary', {
active: lastValue === AC_MODE.COOLING
})}
onClick={cooling}
>
<Text id={`deviceFeatureAction.category.${category}.${type}.cooling`} plural={AC_MODE.HEATING} />
</button>
<button
class={cx('btn btn-sm', 'btn-secondary', {
active: lastValue === AC_MODE.HEATING
})}
onClick={heating}
>
<Text id={`deviceFeatureAction.category.${category}.${type}.heating`} plural={AC_MODE.HEATING} />
</button>
<div class="justify-content-end">
<div class="form-group mb-0">
<select value={lastValue} onChange={updateValue} class="form-control form-control-sm">
{MODE_OPTIONS.map(option => (
<option value={option.value} key={option.value}>
<Text id={`deviceFeatureAction.category.${category}.${type}.${option.i18nKey}`} />
</option>
))}
</select>
</div>
</div>
</td>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import get from 'get-value';
import { Text } from 'preact-i18n';

import { DeviceFeatureCategoriesIcon } from '../../../../utils/consts';
import { AC_SWING_HORIZONTAL, AC_SWING_VERTICAL, DEVICE_FEATURE_TYPES } from '../../../../../../server/utils/constants';

const SWING_HORIZONTAL_OPTIONS = [
{ value: AC_SWING_HORIZONTAL.OFF, i18nKey: 'off' },
{ value: AC_SWING_HORIZONTAL.SAME, i18nKey: 'same' },
{ value: AC_SWING_HORIZONTAL.OPPOSITE, i18nKey: 'opposite' }
];

const SWING_VERTICAL_OPTIONS = [
{ value: AC_SWING_VERTICAL.OFF, i18nKey: 'off' },
{ value: AC_SWING_VERTICAL.SWING, i18nKey: 'swing' },
{ value: AC_SWING_VERTICAL.POSITION_1, i18nKey: 'position-1' },
{ value: AC_SWING_VERTICAL.POSITION_2, i18nKey: 'position-2' },
{ value: AC_SWING_VERTICAL.POSITION_3, i18nKey: 'position-3' },
{ value: AC_SWING_VERTICAL.POSITION_4, i18nKey: 'position-4' },
{ value: AC_SWING_VERTICAL.POSITION_5, i18nKey: 'position-5' }
];

const AirConditioningSwingDeviceFeature = props => {
const { deviceFeature } = props;
const { category, type } = deviceFeature;
const rawValue = deviceFeature.last_value;
const lastValue = rawValue != null && !Number.isNaN(Number(rawValue)) ? Number(rawValue) : rawValue;
const options =
type === DEVICE_FEATURE_TYPES.AIR_CONDITIONING.SWING_HORIZONTAL ? SWING_HORIZONTAL_OPTIONS : SWING_VERTICAL_OPTIONS;

const updateValue = e => {
props.updateValueWithDebounce(deviceFeature, Number(e.currentTarget.value));
};

return (
<tr>
<td>
<i class={`fe fe-${get(DeviceFeatureCategoriesIcon, `${category}.${type}`, { default: 'refresh-cw' })}`} />
</td>
<td>{props.rowName}</td>

<td class="py-0">
<div class="justify-content-end">
<div class="form-group mb-0">
<select value={lastValue} onChange={updateValue} class="form-control form-control-sm">
{options.map(option => (
<option value={option.value} key={option.value}>
<Text id={`deviceFeatureAction.category.${category}.${type}.${option.i18nKey}`} />
</option>
))}
</select>
</div>
</div>
</td>
</tr>
);
};

export default AirConditioningSwingDeviceFeature;
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ const PilotWireModeDeviceFeature = ({ children, ...props }) => {
<option value={PILOT_WIRE_MODE.COMFORT}>
<Text id={`deviceFeatureAction.category.${category}.${type}.comfort`} />
</option>
<option value={PILOT_WIRE_MODE.PROGRAMMING}>
<Text id={`deviceFeatureAction.category.${category}.${type}.programming`} />
</option>
<option value={PILOT_WIRE_MODE.THERMOSTAT}>
<Text id={`deviceFeatureAction.category.${category}.${type}.thermostat`} />
</option>
</select>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Text } from 'preact-i18n';

const PilotWireModeDeviceValue = ({ deviceFeature }) => (
<div>
{deviceFeature.last_value === null && <Text id="dashboard.boxes.devicesInRoom.noValue" />}
{deviceFeature.last_value !== null && (
<Text
id={`deviceFeatureValue.category.${deviceFeature.category}.${deviceFeature.type}.${deviceFeature.last_value}`}
/>
)}
</div>
);

export default PilotWireModeDeviceValue;
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import NoRecentValueBadge from './NoRecentValueBadge';
import TemperatureSensorDeviceValue from './TemperatureSensorDeviceValue';
import LevelSensorDeviceValue from './LevelSensorDeviceValue';
import PressureSensorDeviceValue from './PressureSensorDeviceValue';
import PilotWireModeDeviceValue from './PilotWireModeDeviceValue';

const DISPLAY_BY_FEATURE_CATEGORY = {
[DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR]: MotionSensorDeviceValue,
Expand Down Expand Up @@ -50,7 +51,8 @@ const DISPLAY_BY_FEATURE_TYPE = {
[DEVICE_FEATURE_TYPES.ELECTRICAL_VEHICLE_CLIMATE.INDOOR_TEMPERATURE]: TemperatureSensorDeviceValue,
[DEVICE_FEATURE_TYPES.ELECTRICAL_VEHICLE_BATTERY.BATTERY_RANGE_ESTIMATE]: DistanceSensorDeviceValue,
[DEVICE_FEATURE_TYPES.ELECTRICAL_VEHICLE_STATE.ODOMETER]: DistanceSensorDeviceValue,
[DEVICE_FEATURE_TYPES.ELECTRICAL_VEHICLE_STATE.TIRE_PRESSURE]: PressureSensorDeviceValue
[DEVICE_FEATURE_TYPES.ELECTRICAL_VEHICLE_STATE.TIRE_PRESSURE]: PressureSensorDeviceValue,
[DEVICE_FEATURE_TYPES.HEATER.PILOT_WIRE_MODE]: PilotWireModeDeviceValue
};

const DEVICE_FEATURES_WITHOUT_EXPIRATION = [
Expand Down
Loading
Loading