@ledvance/base 1.3.61 → 1.3.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5973,7 +5973,7 @@ export default {
5973
5973
  "btsolar_groups_inductionsync_description": "Den Bewegungssensor aller Lampen zu synchronisieren, so dass, wenn eine von ihnen eine Bewegung erkennt, auch die anderen eingeschaltet werden.",
5974
5974
  "camera_calibration": "Kamerakalibrierung",
5975
5975
  "camera_calibration_desc": "Die Kamerakalibrierung dauert ca. 25 Sekunden. Möchtest Du fortfahren?",
5976
- "camera_edit_site_name": "Ort-Namen bearbeiten",
5976
+ "camera_edit_site_name": "Standortnamen bearbeiten",
5977
5977
  "camera_errmsg_site_point_limit": "Die Standortüberwachung konnte nicht aktiviert werden, da weniger als 2 Standorte hinzugefügt wurden.",
5978
5978
  "camera_feature_1_headline": "Sirene",
5979
5979
  "camera_feature_2_headline": "Mikrofon",
@@ -6047,10 +6047,10 @@ export default {
6047
6047
  "camera_settings_talk_mode_firstbox_option2_topic": "Beidseitige Kommunikation",
6048
6048
  "camera_settings_talk_mode_secondtopic": "Die Sprache kann von der Umgebung beeinflusst werden. Je nach Situation empfehlen wir entweder ein- oder beidseitige-Kommunikation.",
6049
6049
  "camera_settings_talk_mode_topic": "Gesprächsmodus",
6050
- "camera_site": "Ort",
6051
- "camera_site_delete_dialog_title": "Möchtest Du die Orte wirklich löschen?",
6052
- "camera_site_name": "Ort-name",
6053
- "camera_site_overview_empty_button_add_text": "Ort hinzufügen",
6050
+ "camera_site": "Standort",
6051
+ "camera_site_delete_dialog_title": "Möchtest Du den Standort wirklich löschen?",
6052
+ "camera_site_name": "Standortname",
6053
+ "camera_site_overview_empty_button_add_text": "Standort hinzufügen",
6054
6054
  "camera_site_overview_empty_information_text": "Du hast noch keine Ort hinzugefügt",
6055
6055
  "camera_site_overview_warning_max_number_text": "Die maximale Anzahl an Orte wurde erreicht.",
6056
6056
  "camera_status_indicator": "Statusanzeige",
@@ -6486,7 +6486,7 @@ export default {
6486
6486
  "hybrid_switchstate_setting3": "Einstellung 3",
6487
6487
  "hybrid_switchstate_setting3_description": "Schaltertaste",
6488
6488
  "hybrid_switchstate_setting_text": "Schaltereinstellungen",
6489
- "hybrid_switchstate_title": "Zustand des Schalters",
6489
+ "hybrid_switchstate_title": "Schalterkonfiguration",
6490
6490
  "infobutton_totalenergy": "Die Gesamtenergie zeigt nur die gesamten Verbrauchs-/Erzeugungsdaten nach dem letzten Reset an.\nDie Daten wurden an folgenden Tagen umgeschaltet:",
6491
6491
  "intermittent_time": "Unterbrechungsdauer",
6492
6492
  "irrigation": "Bewässerung",
@@ -6889,7 +6889,7 @@ export default {
6889
6889
  "switch_4channels4setting": "Schalter 4 Einstellung",
6890
6890
  "switch_active_timer_field_small_off_text": "Schalter aus bei {0}",
6891
6891
  "switch_active_timer_field_small_on_text": "Schalter ein in {0}",
6892
- "switch_doublepress": "Doppelt drücken",
6892
+ "switch_doublepress": "Doppeltes Drücken",
6893
6893
  "switch_interlock": "Verriegelung",
6894
6894
  "switch_interlock_addbtn_text": "Verriegelung hinzufügen",
6895
6895
  "switch_interlock_addtitle": "Eine neue Verriegelung hinzufügen",
@@ -6897,10 +6897,10 @@ export default {
6897
6897
  "switch_interlock_editbtn_text": "Verriegelung löschen",
6898
6898
  "switch_interlock_edittitle": "Bearbeiten der Verriegelung",
6899
6899
  "switch_interlockingdescription": "Um die Bedienung jeweils nur eines Schalters zu ermöglichen",
6900
- "switch_longpress": "Langes drücken",
6900
+ "switch_longpress": "Langes Drücken",
6901
6901
  "switch_overcharge_headline_description": "Die Funktion schaltet das Aufladen Deiner mobilen Geräte, einschließlich Mobiltelefone und Powerbanks, automatisch aus, wenn sie vollständig aufgeladen sind, um ein Überladen zu verhindern und die Akkulaufzeit zu verlängern.",
6902
6902
  "switch_overcharge_headline_text": "Überladeschutz",
6903
- "switch_singlepress": "Einmal drücken",
6903
+ "switch_singlepress": "Einmaliges Drücken",
6904
6904
  "switchdescription_energy": "Beachte, dass die Gesamtenergiedaten zurückgesetzt werden und nicht wiederhergestellt werden können.",
6905
6905
  "switchinching_overview_description_text": "Um das Gerät nach einer bestimmten Zeit automatisch auszuschalten.",
6906
6906
  "switchmodule_switch1description": "Schalter 1 Beschreibung",
@@ -6909,11 +6909,11 @@ export default {
6909
6909
  "switchmodule_switch2title": "Schalter 2",
6910
6910
  "switchmodule_switchdescription": "Beschreibung des Schalters",
6911
6911
  "switchmodule_switchtitle": "Wechseln",
6912
- "switchmodule_typesetting": "Zustand des Schalters",
6912
+ "switchmodule_typesetting": "Schalterkonfiguration",
6913
6913
  "switchmodule_typesetting1": "Jedes Umschalten des Wandschalters löst eine Änderung des Gerätezustands aus.",
6914
6914
  "switchmodule_typesetting2": "Die Positionen der Wandschalter entsprechen festen EIN- und AUS-Zuständen. Durch Einschalten des Schalters wird das Gerät eingeschaltet. Ist es bereits eingeschaltet, wird der Befehl ignoriert und der Zustand bleibt unverändert.",
6915
6915
  "switchmodule_typesetting3": "Wenn dein Wandschalter nur in der EIN-Position bleibt, während er gedrückt wird, und automatisch in die AUS-Position zurückkehrt, wenn er losgelassen wird, verhält er sich wie ein Taster.",
6916
- "switchmodule_typesettingdescription": "So konfigurierst du die Einstellung für den Schaltzustand",
6916
+ "switchmodule_typesettingdescription": "So konfigurierst du die Einstellung für den Wandschalter",
6917
6917
  "switchname_1channel": "Smarte Schalter 1 Kanal",
6918
6918
  "switchname_2channel": "Smarte Schalter 2 Kanal",
6919
6919
  "switchname_4channel": "Smarte Schalter 4 Kanal",
@@ -1,6 +1,8 @@
1
1
  import {commonApi} from '@tuya/tuya-panel-api'
2
2
  import { IGetDpResultByHourResponse, IGetDpResultByMonthResponse } from '@tuya/tuya-panel-api/lib/common/interface'
3
3
  import {sendAppEvent} from "../api/native";
4
+ import {retryWithBackoff} from "../utils/index";
5
+ import {TYSdk} from "tuya-panel-kit";
4
6
 
5
7
  export interface PagingResult<T> {
6
8
  data: T
@@ -148,3 +150,133 @@ export async function getDpResultByHour(
148
150
  }
149
151
  }
150
152
  }
153
+
154
+ /**
155
+ * 获取设备所有数据点记录(支持失败重试)
156
+ * @param commonApi API实例
157
+ * @param devId 设备ID
158
+ * @param dpIds 数据点ID,如 '19'
159
+ * @param sortType 排序方式
160
+ * @param retryOptions 重试选项
161
+ * @returns 所有数据点记录
162
+ */
163
+ export async function getAllDpReportLogs(
164
+ devId: string,
165
+ dpIds: string[],
166
+ sortType: 'ASC' | 'DESC' = 'ASC',
167
+ retryOptions: {
168
+ maxRetries?: number;
169
+ initialDelay?: number;
170
+ maxDelay?: number;
171
+ backoffFactor?: number;
172
+ } = {}
173
+ ): Promise<DpReportSataData[]> {
174
+ const limit = 100; // 每次请求的数据量
175
+ let offset = 1;
176
+ let hasNext = true;
177
+ const allDps: DpReportSataData[] = [];
178
+
179
+ while (hasNext) {
180
+ try {
181
+ // 使用重试函数包装API调用
182
+ const res: DpReportSataResData = await retryWithBackoff(
183
+ () => commonApi.statApi.getDpReportLog({
184
+ devId,
185
+ dpIds: dpIds.join(','),
186
+ offset,
187
+ limit,
188
+ sortType
189
+ }),
190
+ {
191
+ ...retryOptions,
192
+ // 自定义判断哪些错误需要重试
193
+ shouldRetry: (error) => {
194
+ // 网络错误、超时错误或服务器错误(5xx)通常需要重试
195
+ const isNetworkError = error.name === 'NetworkError' ||
196
+ error.name === 'TimeoutError' ||
197
+ (error.response && error.response.status >= 500);
198
+
199
+ // 对于特定的业务错误码也可以在这里添加判断
200
+ return isNetworkError;
201
+ }
202
+ }
203
+ );
204
+
205
+ allDps.push(...res.dps);
206
+
207
+ if (res.hasNext) {
208
+ offset += limit;
209
+ } else {
210
+ hasNext = false;
211
+ }
212
+ } catch (error) {
213
+ console.error('获取数据点记录失败,不再继续获取:', error);
214
+ hasNext = false;
215
+ }
216
+ }
217
+
218
+ return allDps;
219
+ }
220
+
221
+ export const saveDeviceExtInfo = async (devId: string, key: string, value: string): Promise<boolean> => {
222
+ try {
223
+ return await new Promise<any>((resolve, reject) => {
224
+ TYSdk.native.apiRNRequest(
225
+ {
226
+ v: "1.0",
227
+ postData: {
228
+ value: value,
229
+ key: key,
230
+ devId: devId
231
+ },
232
+ a: "tuya.m.solution.device.storage.save"
233
+ },
234
+ (success: any) => {
235
+ console.log('tuya.m.solution.device.storage.save success', success)
236
+ resolve(success)
237
+ },
238
+ (error: any) => {
239
+ console.log('tuya.m.solution.device.storage.save error', error)
240
+ reject(error)
241
+ }
242
+ )
243
+ })
244
+ } catch (error) {
245
+ console.log('saveDeviceExtInfo error', error)
246
+ return false
247
+ }
248
+ }
249
+
250
+ export const getDeviceExtInfo = async (devId: string, key: string): Promise<string | null> => {
251
+ try {
252
+ const success = await new Promise<any>((resolve, reject) => {
253
+ TYSdk.native.apiRNRequest(
254
+ {
255
+ v: "1.0",
256
+ postData: {
257
+ "key": key,
258
+ "devId": devId
259
+ },
260
+ a: "tuya.m.solution.device.storage.get"
261
+ },
262
+ (success: any) => {
263
+ console.log('tuya.m.solution.device.storage.get success', success)
264
+ resolve(success)
265
+ },
266
+ (error: any) => {
267
+ console.log('tuya.m.solution.device.storage.get error', error)
268
+ reject(error)
269
+ }
270
+ )
271
+ })
272
+
273
+ let data = success
274
+ if (typeof success === 'string') {
275
+ data = JSON.parse(success)
276
+ }
277
+ return data.value
278
+ } catch (error) {
279
+ console.log('getDeviceExtInfo error', error)
280
+ return null
281
+ }
282
+ }
@@ -24,6 +24,7 @@ export interface NativeProps {
24
24
  is24HourClock: boolean
25
25
  timeZone: string
26
26
  gestureControlValues: GestureControlType
27
+ newPalette?: boolean
27
28
  }
28
29
 
29
30
  interface FlagModeState {
@@ -34,6 +35,7 @@ interface FlagModeState {
34
35
  export interface DeviceInfo {
35
36
  devId: string
36
37
  pId: string
38
+ category?: string
37
39
  dps: any
38
40
  }
39
41
 
@@ -86,7 +88,8 @@ const initialState: NativeProps = {
86
88
  timeZone: 'Europe/Berlin',
87
89
  gestureControlValues: {
88
90
  isEnd: false
89
- }
91
+ },
92
+ newPalette: false
90
93
  }
91
94
 
92
95
  // energy generation
@@ -113,6 +116,9 @@ const nativePropsSlice = createSlice({
113
116
  if (!!action.payload.deviceInfo.pId) {
114
117
  state.deviceInfo.pId = action.payload.deviceInfo.pId
115
118
  }
119
+ if (!!action.payload.deviceInfo.category) {
120
+ state.deviceInfo.category = action.payload.deviceInfo.category
121
+ }
116
122
  state.deviceInfo.dps = { ...state.deviceInfo.dps, ...action.payload.deviceInfo.dps }
117
123
  state.initialDps = { ...state.initialDps, ...action.payload.initialDps }
118
124
  },
@@ -184,6 +190,9 @@ const nativePropsSlice = createSlice({
184
190
  keys.forEach(key => {
185
191
  state.gestureControlValues[key] = action.payload[key]
186
192
  })
193
+ },
194
+ setNewPalette(state, action: PayloadAction<boolean>) {
195
+ state.newPalette = action.payload
187
196
  }
188
197
  },
189
198
  })
@@ -231,6 +240,10 @@ const useDeviceId = () => {
231
240
  return useSelector(store => store.ldvModules.deviceInfo.devId)
232
241
  }
233
242
 
243
+ const useDeviceCategory = () => {
244
+ return useSelector(store => store.ldvModules.deviceInfo.category)
245
+ }
246
+
234
247
  const useGroupId = () => {
235
248
  return useSelector(store => store.ldvModules.uaGroupInfo.tyGroupId)
236
249
  }
@@ -471,6 +484,10 @@ function useGestureControl<K extends keyof GestureControlType>(key: K): [Gesture
471
484
  return [value]
472
485
  }
473
486
 
487
+ const useNewPalette = () => {
488
+ return useSelector(store => store.ldvModules.newPalette)
489
+ }
490
+
474
491
  export const useFanMaxSpeed = () => {
475
492
  const { productId } = useDeviceInfo()
476
493
  return fanProductList.includes(productId) ? 20 : 3
@@ -497,6 +514,7 @@ export const {
497
514
  setTimeZone,
498
515
  setEnergieverbrauch,
499
516
  setGestureControlValues,
517
+ setNewPalette,
500
518
  } = nativePropsSlice.actions
501
519
 
502
520
  export {
@@ -522,5 +540,7 @@ export {
522
540
  useTimeZone,
523
541
  useTimeZoneCity,
524
542
  useEnergieverbrauch,
525
- useGestureControl
543
+ useGestureControl,
544
+ useDeviceCategory,
545
+ useNewPalette
526
546
  }
@@ -19,17 +19,49 @@ export const loopsText = [
19
19
  I18n.getLang('timeschedule_add_schedule_weekday6_text'),
20
20
  ]
21
21
 
22
- export const loopText = (loop, time = '') => {
23
- let isToday = true
22
+ /**
23
+ * 根据循环设置和时间生成循环文本描述
24
+ * @param {number[]|string[]} loop - 表示每周哪几天启用的数组,1表示启用,0表示不启用
25
+ * @param {string} time - 可选的时间字符串,格式为 "HH:MM"
26
+ * @returns {string} 格式化后的循环文本
27
+ */
28
+ export const loopText = (loop: number[] | string[], time: string = ''): string => {
29
+ // 判断是否为今天(如果提供了时间)
30
+ let isToday = true;
24
31
  if (time) {
25
- const currentTime = dayjs()
26
- const targetTime = dayjs().set('hour', parseInt(time.split(':')[0])).set('minute', parseInt(time.split(':')[1]));
27
- const isBeforeCurrentTime = targetTime.isBefore(currentTime)
28
- isToday = !isBeforeCurrentTime
32
+ const [hours, minutes] = time.split(':').map(Number);
33
+ const currentTime = dayjs();
34
+ const targetTime = dayjs().set('hour', hours).set('minute', minutes);
35
+ isToday = !targetTime.isBefore(currentTime);
29
36
  }
30
- const loopStrArray = loopsText.filter((_item, index) => Number(loop[index]) === 1)
31
- return loopStrArray.length === 0 ? (I18n.getLang(isToday ? 'motion_detection_time_schedule_notifications_field_weekdays_text2' : 'motion_detection_time_schedule_notifications_field_weekdays_text3')) : loopStrArray.length === 7 ? I18n.getLang('motion_detection_time_schedule_notifications_field_weekdays_text4') : loopStrArray.join(' ')
32
- }
37
+
38
+ // 将循环数组转换为带有启用状态的对象数组
39
+ const weekdaysWithStatus = loopsText.map((title, index) => ({
40
+ title,
41
+ enable: Number(loop[index]) === 1
42
+ }));
43
+
44
+ // 将周日移到数组末尾(如果需要按周一到周日的顺序显示)
45
+ const first = weekdaysWithStatus.shift();
46
+ first && weekdaysWithStatus.push(first);
47
+
48
+ // 获取已启用的星期几
49
+ const enabledWeekdays = weekdaysWithStatus
50
+ .filter(item => item.enable)
51
+ .map(item => item.title);
52
+
53
+ // 根据启用的天数返回不同的文本
54
+ switch (enabledWeekdays.length) {
55
+ case 0:
56
+ return I18n.getLang(isToday
57
+ ? 'motion_detection_time_schedule_notifications_field_weekdays_text2'
58
+ : 'motion_detection_time_schedule_notifications_field_weekdays_text3');
59
+ case 7:
60
+ return I18n.getLang('motion_detection_time_schedule_notifications_field_weekdays_text4');
61
+ default:
62
+ return enabledWeekdays.join(' ');
63
+ }
64
+ };
33
65
 
34
66
  const tommorrow = () => {
35
67
  const text = I18n.getLang('feature_summary_frequency_txt_2').split(' ')
@@ -189,3 +189,61 @@ export function abbreviateMonths(str: string) {
189
189
  export function overDays(date: string, days: number): boolean {
190
190
  return dayjs().diff(dayjs(date), 'days') >= days
191
191
  }
192
+
193
+
194
+ /**
195
+ * 通用重试函数,支持指数退避算法
196
+ * @param fn 需要重试的异步函数
197
+ * @param options 重试选项
198
+ * @returns 异步函数的结果
199
+ */
200
+ export async function retryWithBackoff<T>(
201
+ fn: () => Promise<T>,
202
+ options: {
203
+ maxRetries?: number; // 最大重试次数
204
+ initialDelay?: number; // 初始延迟时间(毫秒)
205
+ maxDelay?: number; // 最大延迟时间(毫秒)
206
+ backoffFactor?: number; // 退避因子
207
+ shouldRetry?: (error: any) => boolean; // 自定义判断是否应该重试的函数
208
+ } = {}
209
+ ): Promise<T> {
210
+ const {
211
+ maxRetries = 3,
212
+ initialDelay = 1000,
213
+ maxDelay = 30000,
214
+ backoffFactor = 2,
215
+ shouldRetry = () => true
216
+ } = options;
217
+
218
+ let retries = 0;
219
+ let delay = initialDelay;
220
+
221
+ const execute = async (): Promise<T> => {
222
+ try {
223
+ return await fn();
224
+ } catch (error) {
225
+ if (retries >= maxRetries || !shouldRetry(error)) {
226
+ throw error;
227
+ }
228
+
229
+ retries++;
230
+
231
+ // 计算下一次重试的延迟时间(指数退避)
232
+ delay = Math.min(delay * backoffFactor, maxDelay);
233
+
234
+ // 添加一些随机性,避免多个请求同时重试
235
+ const jitter = delay * 0.2 * Math.random();
236
+ const actualDelay = delay + jitter;
237
+
238
+ console.log(`请求失败,${retries}/${maxRetries} 次重试,等待 ${Math.round(actualDelay)}ms...`, error);
239
+
240
+ // 等待延迟时间
241
+ await new Promise(resolve => setTimeout(resolve, actualDelay));
242
+
243
+ // 递归重试
244
+ return execute();
245
+ }
246
+ };
247
+
248
+ return execute();
249
+ }