iobroker.leapmotor 0.5.8 → 0.6.2

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.
package/README.md CHANGED
@@ -2,10 +2,10 @@
2
2
 
3
3
  # ioBroker.leapmotor
4
4
 
5
- [![Version](https://img.shields.io/badge/version-0.5.7-blue.svg)](https://github.com/backfisch88/ioBroker.leapmotor)
5
+ [![Version](https://img.shields.io/badge/version-0.6.0-blue.svg)](https://github.com/backfisch88/ioBroker.leapmotor)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
7
 
8
- Unofficial Leapmotor electric vehicle integration for ioBroker. Tested on T03.
8
+ Unofficial [Leapmotor](https://www.leapmotor.com/) electric vehicle integration for ioBroker. Tested on T03.
9
9
 
10
10
  ## ⚠️ Important: Use a Second Account
11
11
 
@@ -142,29 +142,28 @@ Comfort commands (only created/shown if the vehicle model supports the feature):
142
142
  | cmd.hotspot_on / off | Wi-Fi hotspot (no effect on T03) |
143
143
 
144
144
  Which comfort commands actually appear depends on the detected vehicle model — see
145
- `src/vehicleCapabilities.js` in the repository for the current capability matrix per model.
145
+ `admin-tab/src/vehicleCapabilities.js` in the repository for the current capability matrix per model.
146
146
 
147
147
  ## Changelog
148
+ ### 0.6.2 (2026-07-08)
149
+ - Fix: B10 model now correctly uses the c10 cloud status endpoint (community-confirmed), resolving empty status/trips/charging datapoints
150
+ - Fix: enabled full i18n for jsonConfig.json now that admin/i18n translation files cover all keys
151
+
152
+ ### 0.6.1 (2026-07-03)
153
+ - Fix: repository checker findings - node: prefix for built-in modules, removed raw setTimeout fallback, included admin-tab i18n source in npm package, trimmed news list to 7 entries
154
+
155
+ ### 0.6.0 (2026-07-03)
156
+ - Refactor: moved to standard plain-JS repository layout (main.js at repository root, supporting modules under lib/ instead of build/)
157
+ - Fix: removed dead/duplicate code, added VIN sanitization for object IDs, subscribed and acknowledged config.* states
158
+ - Fix: enforced upper bound on polling interval in code, switched picture cache from package-directory file to adapter's own file storage
159
+ - Fix: translated remaining German backend strings to English, enabled compact mode support, adapter-managed timers used throughout
160
+
148
161
  ### 0.5.8 (2026-07-02)
149
162
  - Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test
150
163
 
151
164
  ### 0.5.7 (2026-06-29)
152
165
  - Fix: avoid npm transparency log conflict from a previous failed publish attempt (no functional changes vs. 0.5.5)
153
166
 
154
- ### 0.5.6 (2026-06-29)
155
- - New: Trips tab showing daily kilometers with individual detected trips and an "Other" entry for any unaccounted distance
156
- - Fix: trip detection now backfills kilometers driven before the trip was first detected (closes the gap caused by the 5-minute polling interval)
157
- - Fix: critical bug where `adminTab.link` used a relative path, causing a 404 error when opening the tab for all users — now uses an absolute path
158
- - Fix: admin tab files (`index_m.html`, `tab.html`, `tab.js`, `tab_m.html`) were missing from the published package; they are now included
159
- - Fix: `index_m.html` contained leftover placeholder content instead of the real mobile tab loader
160
-
161
- ### 0.5.5 (2026-06-26)
162
- - Maintenance: dependency cleanup and repository checker compliance fixes
163
-
164
- ### 0.5.4 (2026-06-26)
165
- - Fix: use `window.setTimeout`/`window.setInterval` in the admin tab frontend to satisfy the repository checker
166
- - Maintenance: dependency cleanup
167
-
168
167
  Older changes can be found in [CHANGELOG_OLD.md](CHANGELOG_OLD.md).
169
168
 
170
169
  ## License
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "Für alle Fernbefehle ist eine 4-stellige PIN erforderlich",
3
+ "How often to fetch vehicle status (1-60)": "Wie oft soll der Fahrzeugstatus abgerufen werden (1-60)",
4
+ "Language": "Sprache",
5
+ "Leapmotor E-Mail": "E-Mail von Leapmotor",
6
+ "Password": "Passwort",
7
+ "Polling interval (minutes)": "Abfrageintervall (Minuten)",
8
+ "Use a dedicated second account (see README)": "Verwenden Sie ein dediziertes zweites Konto (siehe README)",
9
+ "Vehicle PIN": "Fahrzeug-PIN"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "Leapmotor E-Mail": "Leapmotor E-Mail",
3
+ "Use a dedicated second account (see README)": "Use a dedicated second account (see README)",
4
+ "Password": "Password",
5
+ "Vehicle PIN": "Vehicle PIN",
6
+ "4-digit PIN required for all remote commands": "4-digit PIN required for all remote commands",
7
+ "Polling interval (minutes)": "Polling interval (minutes)",
8
+ "How often to fetch vehicle status (1-60)": "How often to fetch vehicle status (1-60)",
9
+ "Language": "Language"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "Se requiere PIN de 4 dígitos para todos los comandos remotos",
3
+ "How often to fetch vehicle status (1-60)": "Con qué frecuencia recuperar el estado del vehículo (1-60)",
4
+ "Language": "Idioma",
5
+ "Leapmotor E-Mail": "Correo electrónico de Leapmotor",
6
+ "Password": "Contraseña",
7
+ "Polling interval (minutes)": "Intervalo de sondeo (minutos)",
8
+ "Use a dedicated second account (see README)": "Utilice una segunda cuenta dedicada (consulte README)",
9
+ "Vehicle PIN": "PIN del vehículo"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "Code PIN à 4 chiffres requis pour toutes les commandes à distance",
3
+ "How often to fetch vehicle status (1-60)": "À quelle fréquence récupérer le statut du véhicule (1-60)",
4
+ "Language": "Langue",
5
+ "Leapmotor E-Mail": "Courriel de Leapmotor",
6
+ "Password": "Mot de passe",
7
+ "Polling interval (minutes)": "Intervalle d'interrogation (minutes)",
8
+ "Use a dedicated second account (see README)": "Utilisez un deuxième compte dédié (voir README)",
9
+ "Vehicle PIN": "Code PIN du véhicule"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "PIN di 4 cifre richiesto per tutti i comandi remoti",
3
+ "How often to fetch vehicle status (1-60)": "Con quale frequenza recuperare lo stato del veicolo (1-60)",
4
+ "Language": "Lingua",
5
+ "Leapmotor E-Mail": "E-mail di Leapmotor",
6
+ "Password": "Password",
7
+ "Polling interval (minutes)": "Intervallo di polling (minuti)",
8
+ "Use a dedicated second account (see README)": "Utilizza un secondo account dedicato (vedi README)",
9
+ "Vehicle PIN": "PIN del veicolo"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "4-cijferige pincode vereist voor alle afstandsbedieningsopdrachten",
3
+ "How often to fetch vehicle status (1-60)": "Hoe vaak voertuigstatus ophalen (1-60)",
4
+ "Language": "Taal",
5
+ "Leapmotor E-Mail": "Leapmotor-e-mail",
6
+ "Password": "Wachtwoord",
7
+ "Polling interval (minutes)": "Polling-interval (minuten)",
8
+ "Use a dedicated second account (see README)": "Gebruik een speciaal tweede account (zie README)",
9
+ "Vehicle PIN": "Voertuigpincode"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "Do wszystkich poleceń zdalnych wymagany jest 4-cyfrowy PIN",
3
+ "How often to fetch vehicle status (1-60)": "Jak często pobierać status pojazdu (1-60)",
4
+ "Language": "Język",
5
+ "Leapmotor E-Mail": "Poczta elektroniczna Leapmotor",
6
+ "Password": "Hasło",
7
+ "Polling interval (minutes)": "Interwał odpytywania (minuty)",
8
+ "Use a dedicated second account (see README)": "Użyj dedykowanego drugiego konta (patrz README)",
9
+ "Vehicle PIN": "PIN pojazdu"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "PIN de 4 dígitos necessário para todos os comandos remotos",
3
+ "How often to fetch vehicle status (1-60)": "Com que frequência buscar o status do veículo (1-60)",
4
+ "Language": "Linguagem",
5
+ "Leapmotor E-Mail": "E-mail da Leapmotor",
6
+ "Password": "Senha",
7
+ "Polling interval (minutes)": "Intervalo de pesquisa (minutos)",
8
+ "Use a dedicated second account (see README)": "Use uma segunda conta dedicada (consulte README)",
9
+ "Vehicle PIN": "PIN do veículo"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "Для всех удаленных команд требуется 4-значный PIN-код.",
3
+ "How often to fetch vehicle status (1-60)": "Как часто получать статус автомобиля (1-60)",
4
+ "Language": "Язык",
5
+ "Leapmotor E-Mail": "Электронная почта Leapmotor",
6
+ "Password": "Пароль",
7
+ "Polling interval (minutes)": "Интервал опроса (минуты)",
8
+ "Use a dedicated second account (see README)": "Используйте выделенную вторую учетную запись (см. README).",
9
+ "Vehicle PIN": "PIN-код автомобиля"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "Для всіх дистанційних команд необхідний 4-значний PIN-код",
3
+ "How often to fetch vehicle status (1-60)": "Як часто отримувати статус транспортного засобу (1-60)",
4
+ "Language": "Мова",
5
+ "Leapmotor E-Mail": "Електронна пошта Leapmotor",
6
+ "Password": "Пароль",
7
+ "Polling interval (minutes)": "Інтервал опитування (хв)",
8
+ "Use a dedicated second account (see README)": "Використовуйте виділений другий обліковий запис (див. README)",
9
+ "Vehicle PIN": "ПІН транспортного засобу"
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "4-digit PIN required for all remote commands": "所有远程命令都需要 4 位 PIN",
3
+ "How often to fetch vehicle status (1-60)": "获取车辆状态的频率 (1-60)",
4
+ "Language": "语言",
5
+ "Leapmotor E-Mail": "零跑电子邮箱",
6
+ "Password": "密码",
7
+ "Polling interval (minutes)": "轮询间隔(分钟)",
8
+ "Use a dedicated second account (see README)": "使用专用的第二个帐户(请参阅自述文件)",
9
+ "Vehicle PIN": "车辆密码"
10
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "type": "panel",
3
- "i18n": false,
3
+ "i18n": true,
4
4
  "items": {
5
5
  "email": {
6
6
  "type": "text",
@@ -0,0 +1,134 @@
1
+ // Translation dictionary for the Leapmotor admin-tab React dashboard.
2
+ // Convention (matches @iobroker/adapter-react-v5 I18n): the English text itself is
3
+ // used as the lookup key. I18n.t('Some Text') automatically falls back to the key
4
+ // (i.e. English) if no translation is found for the active language, so English is
5
+ // always the guaranteed baseline even if a language is missing or incomplete.
6
+ const translations = {
7
+ en: {},
8
+ de: {
9
+ 'Connecting...': 'Verbinde...',
10
+ 'Dashboard': 'Dashboard',
11
+ 'Consumption': 'Verbrauch',
12
+ 'Trips': 'Fahrten',
13
+ 'Datapoints': 'Datenpunkte',
14
+ 'Diagnostics': 'Diagnose',
15
+ 'No vehicle found. Is the adapter running?': 'Kein Fahrzeug gefunden. Ist der Adapter gestartet?',
16
+
17
+ 'Close': 'Zu',
18
+ 'Open': 'Auf',
19
+ 'Window': 'Fenster',
20
+ 'Sunshade': 'Sonnenblende',
21
+ 'COMFORT': 'KOMFORT',
22
+ 'Sentry Mode On': 'Wachmodus an',
23
+ 'Sentry Mode Off': 'Wachmodus aus',
24
+ 'Steering Wheel Heat On': 'Lenkradheizung an',
25
+ 'Steering Wheel Heat Off': 'Lenkradheizung aus',
26
+ 'Mirror/Rear Window Heat On': 'Spiegel-/Heckscheibenheizung an',
27
+ 'Mirror/Rear Window Heat Off': 'Spiegel-/Heckscheibenheizung aus',
28
+ 'Speed Limit (0 = off)': 'Geschwindigkeitsbegrenzung (0 = aus)',
29
+ 'Seat Heat': 'Sitzheizung',
30
+ 'CONNECTIVITY': 'KONNEKTIVITÄT',
31
+ 'Turn Off': 'ausschalten',
32
+ 'Turn On': 'einschalten',
33
+ 'Hotspot': 'Hotspot',
34
+ 'Refresh Status': 'Status aktualisieren',
35
+
36
+ 'LOCKED': 'GESPERRT',
37
+ 'CHARGING': 'LÄDT',
38
+ 'CLIMATE': 'KLIMA',
39
+ 'DOOR OPEN': 'TÜR OFFEN',
40
+ 'OUTSIDE': 'AUSSEN',
41
+ 'RANGE': 'RANGE',
42
+ 'STATUS': 'STATUS',
43
+ 'DOORS': 'TÜREN',
44
+ 'LOCK': 'SCHLOSS',
45
+ 'Closed': 'Zu',
46
+ 'Locked': 'Zu',
47
+ 'Unlocked': 'Offen',
48
+
49
+ 'CLIMATE CONTROL': 'KLIMAANLAGE',
50
+ 'Heat': 'Heizen',
51
+ 'Cool': 'Kühlen',
52
+ 'Vent': 'Lüften',
53
+ 'Off': 'Aus',
54
+ 'Fan Speed': 'Lüfterstufe',
55
+ 'Windshield Defrost (full heat)': 'Frontscheibe Defrost (volle Heizung)',
56
+ 'Battery Preheat Off': 'Batterievorheizung aus',
57
+ 'Preheat Battery': 'Batterie vorheizen',
58
+ 'Quick Cool': 'Schnelles Kühlen',
59
+ 'Quick Heat': 'Schnelles Heizen',
60
+
61
+ 'CHARGE': 'LADEN',
62
+ 'Charge Limit': 'Ladelimit',
63
+ 'Charge Schedule': 'Ladezeitplan',
64
+ 'Active': 'Aktiv',
65
+ 'Inactive': 'Inaktiv',
66
+ 'Start': 'Start',
67
+ 'End': 'Ende',
68
+ 'Apply Schedule': 'Zeitplan anwenden',
69
+
70
+ 'CLIMATE SCHEDULE': 'KLIMA-ZEITPLAN',
71
+ 'Active schedule': 'Aktiver Zeitplan',
72
+ 'Inactive (last': 'Inaktiv (zuletzt',
73
+ 'No schedule set': 'Kein Zeitplan gesetzt',
74
+ 'Climate Schedule': 'Klimazeitplan',
75
+ 'Mode': 'Modus',
76
+ 'Start Time': 'Startzeit',
77
+ 'Repeat': 'Wiederholen',
78
+ 'Mon': 'Mo', 'Tue': 'Di', 'Wed': 'Mi', 'Thu': 'Do', 'Fri': 'Fr', 'Sat': 'Sa', 'Sun': 'So',
79
+ 'Delete': 'Löschen',
80
+
81
+ 'LOCKS & OPENINGS': 'VERRIEGELUNG & ÖFFNUNGEN',
82
+ 'Lock': 'Sperren',
83
+ 'Unlock': 'Öffnen',
84
+ 'Trunk': 'Kofferraum',
85
+ 'Locate Vehicle': 'Fahrzeug orten',
86
+
87
+ 'AVG CONSUMPTION': 'Ø VERBRAUCH',
88
+ 'RANKING': 'RANKING',
89
+ 'TOTAL': 'GESAMT',
90
+ 'BEST WEEK': 'BESTE WOCHE',
91
+ 'WORST WEEK': 'SCHLECHTESTE',
92
+ 'TREND': 'TREND',
93
+ 'vs. average': 'vs. Schnitt',
94
+ 'Consumption over the last 6 weeks': 'Verbrauch der letzten 6 Wochen',
95
+ 'No weekly data available yet.': 'Noch keine Wochendaten verfügbar.',
96
+ 'Consumption': 'Verbrauch',
97
+
98
+ 'TRIP OVERVIEW': 'FAHRTEN-ÜBERSICHT',
99
+ 'Today': 'Heute',
100
+ 'Last 7 days': 'Letzte 7 Tage',
101
+ 'Trip in progress': 'Fahrt läuft gerade',
102
+ 'No trip data recorded yet.': 'Noch keine Fahrtdaten aufgezeichnet.',
103
+ 'trip detected': 'Fahrt erkannt',
104
+ 'trips detected': 'Fahrten erkannt',
105
+ 'Other (untracked trips)': 'Sonstige (nicht erfasste Fahrten)',
106
+ 'battery': 'Akku',
107
+ 'Trips are detected every 5 minutes based on speed. Very short trips between two polls may show up as "Other" instead of being recorded as an individual trip.':
108
+ 'Fahrten werden alle 5 Minuten anhand der Geschwindigkeit erkannt. Sehr kurze Fahrten zwischen zwei Abfragen können als "Sonstige" erscheinen, statt als eigene Fahrt erfasst zu werden.',
109
+
110
+ 'Battery': 'Batterie',
111
+ 'Range & Consumption': 'Reichweite & Verbrauch',
112
+ 'Charging': 'Laden',
113
+ 'Climate': 'Klima',
114
+ 'Driving': 'Fahren',
115
+ 'Safety & Doors': 'Sicherheit & Türen',
116
+ 'Tires': 'Reifen',
117
+ 'Location & Privacy': 'Standort & Datenschutz',
118
+ 'Connectivity': 'Konnektivität',
119
+ 'Other': 'Sonstiges',
120
+
121
+ 'Cloud Connection': 'Cloud-Verbindung',
122
+ 'Connected': 'Verbunden',
123
+ 'Disconnected': 'Getrennt',
124
+ 'Last data update': 'Letztes Daten-Update',
125
+ 'Refresh Status Now': 'Status jetzt aktualisieren',
126
+ 'Vehicle Information': 'Fahrzeuginformationen',
127
+ 'Model': 'Modell',
128
+ 'Year': 'Baujahr',
129
+ 'Steering': 'Lenkrad',
130
+ 'Allocation Code': 'Ausstattungscode',
131
+ },
132
+ };
133
+
134
+ export default translations;
package/io-package.json CHANGED
@@ -1,20 +1,46 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "leapmotor",
4
- "version": "0.5.8",
4
+ "version": "0.6.2",
5
5
  "news": {
6
+ "0.6.2": {
7
+ "en": "Fix: B10 model now correctly uses the c10 cloud status endpoint (community-confirmed), resolving empty status/trips/charging datapoints. Fix: enabled full i18n for jsonConfig.json now that admin/i18n translation files cover all keys.",
8
+ "de": "Fix: B10-Modell nutzt jetzt korrekt den c10-Cloud-Statusendpunkt (community-bestaetigt), behebt leere status/trips/charging-Datenpunkte. Fix: vollstaendiges i18n fuer jsonConfig.json aktiviert, da admin/i18n-Uebersetzungsdateien jetzt alle Schluessel abdecken.",
9
+ "ru": "Исправление: модель B10 теперь корректно использует облачную конечную точку статуса c10 (подтверждено сообществом), что устраняет пустые точки данных status/trips/charging. Исправление: включена полная локализация i18n для jsonConfig.json, так как файлы перевода admin/i18n теперь охватывают все ключи.",
10
+ "pt": "Correção: o modelo B10 agora usa corretamente o endpoint de status c10 na nuvem (confirmado pela comunidade), resolvendo os pontos de dados vazios de status/trips/charging. Correção: i18n completo habilitado para jsonConfig.json, já que os arquivos de tradução admin/i18n agora cobrem todas as chaves.",
11
+ "nl": "Fix: B10-model gebruikt nu correct het c10-cloud statusendpoint (door de community bevestigd), waardoor lege status/trips/charging-datapunten worden opgelost. Fix: volledige i18n ingeschakeld voor jsonConfig.json, aangezien admin/i18n-vertaalbestanden nu alle sleutels dekken.",
12
+ "fr": "Correction : le modèle B10 utilise désormais correctement le point de terminaison de statut cloud c10 (confirmé par la communauté), résolvant les points de données status/trips/charging vides. Correction : i18n complet activé pour jsonConfig.json, les fichiers de traduction admin/i18n couvrant désormais toutes les clés.",
13
+ "it": "Correzione: il modello B10 ora utilizza correttamente l'endpoint di stato cloud c10 (confermato dalla community), risolvendo i datapoint status/trips/charging vuoti. Correzione: i18n completo abilitato per jsonConfig.json, poiché i file di traduzione admin/i18n ora coprono tutte le chiavi.",
14
+ "es": "Corrección: el modelo B10 ahora usa correctamente el endpoint de estado en la nube c10 (confirmado por la comunidad), resolviendo los puntos de datos vacíos de status/trips/charging. Corrección: se habilitó i18n completo para jsonConfig.json, ya que los archivos de traducción admin/i18n ahora cubren todas las claves.",
15
+ "pl": "Poprawka: model B10 poprawnie korzysta teraz z chmurowego punktu końcowego statusu c10 (potwierdzone przez społeczność), co rozwiązuje puste punkty danych status/trips/charging. Poprawka: włączono pełne i18n dla jsonConfig.json, ponieważ pliki tłumaczeń admin/i18n obejmują teraz wszystkie klucze.",
16
+ "uk": "Виправлення: модель B10 тепер коректно використовує хмарну кінцеву точку статусу c10 (підтверджено спільнотою), що вирішує проблему порожніх точок даних status/trips/charging. Виправлення: увімкнено повну локалізацію i18n для jsonConfig.json, оскільки файли перекладу admin/i18n тепер охоплюють усі ключі.",
17
+ "zh-cn": "修复:B10 车型现在正确使用 c10 云状态端点(已由社区确认),解决了 status/trips/charging 数据点为空的问题。修复:由于 admin/i18n 翻译文件现已覆盖所有键,为 jsonConfig.json 启用了完整的 i18n 支持。"
18
+ },
19
+ "0.6.1": {
20
+ "en": "Fix: repository checker findings - use node: prefix for built-in modules, remove raw setTimeout fallback, include admin-tab i18n source in npm package, trim news list to 7 entries.",
21
+ "de": "Fix: Repository-Checker-Befunde behoben - node:-Praefix fuer eingebaute Module verwendet, rohen setTimeout-Fallback entfernt, admin-tab-i18n-Quellcode ins npm-Paket aufgenommen, News-Liste auf 7 Eintraege gekuerzt.",
22
+ "ru": "Исправление: устранены замечания проверки репозитория - использован префикс node: для встроенных модулей, удалён резервный вызов setTimeout, исходный код i18n admin-tab включён в npm-пакет, список новостей сокращён до 7 записей.",
23
+ "pt": "Correção: correções de verificação do repositório - uso do prefixo node: para módulos integrados, remoção do fallback bruto de setTimeout, inclusão do código-fonte i18n do admin-tab no pacote npm, lista de notícias reduzida para 7 entradas.",
24
+ "nl": "Fix: bevindingen van de repository-checker verholpen - node:-prefix gebruikt voor ingebouwde modules, ruwe setTimeout-fallback verwijderd, admin-tab i18n broncode opgenomen in npm-pakket, nieuwslijst teruggebracht tot 7 items.",
25
+ "fr": "Correction : corrections du vérificateur de dépôt - utilisation du préfixe node: pour les modules intégrés, suppression du repli setTimeout brut, inclusion du code source i18n de l'admin-tab dans le paquet npm, liste des actualités réduite à 7 entrées.",
26
+ "it": "Correzione: risolti i rilievi del controllo del repository - usato il prefisso node: per i moduli integrati, rimosso il fallback grezzo di setTimeout, incluso il codice sorgente i18n dell'admin-tab nel pacchetto npm, elenco notizie ridotto a 7 voci.",
27
+ "es": "Corrección: se resolvieron los hallazgos del verificador del repositorio - se usó el prefijo node: para los módulos integrados, se eliminó el fallback bruto de setTimeout, se incluyó el código fuente i18n del admin-tab en el paquete npm, se redujo la lista de noticias a 7 entradas.",
28
+ "pl": "Poprawka: rozwiązano ustalenia weryfikatora repozytorium - użyto prefiksu node: dla modułów wbudowanych, usunięto surowy fallback setTimeout, dołączono kod źródłowy i18n admin-tab do pakietu npm, skrócono listę nowości do 7 pozycji.",
29
+ "uk": "Виправлення: усунено зауваження перевірки репозиторію - використано префікс node: для вбудованих модулів, видалено резервний виклик setTimeout, вихідний код i18n admin-tab включено до npm-пакета, список новин скорочено до 7 записів.",
30
+ "zh-cn": "修复:解决仓库检查器发现的问题 - 为内置模块使用 node: 前缀,移除了原始的 setTimeout 回退,将 admin-tab i18n 源代码包含在 npm 包中,新闻列表精简至 7 条。"
31
+ },
6
32
  "0.5.8": {
7
33
  "en": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
8
34
  "de": "Fix: Repository-Checker-Konformitaet - fehlende Zwischenobjekte ergaenzt (charging/consumption/pictures/trips), ungueltige State-Rollen korrigiert, echten Integrationstest hinzugefuegt.",
9
- "ru": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
10
- "pt": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
11
- "nl": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
12
- "fr": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
13
- "it": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
14
- "es": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
15
- "pl": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
16
- "uk": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test.",
17
- "zh-cn": "Fix: repository checker compliance - added missing intermediate object structure (charging/consumption/pictures/trips channels), corrected invalid state roles, added real integration test."
35
+ "ru": "Исправление: соответствие проверке репозитория - добавлены недостающие промежуточные объекты (charging/consumption/pictures/trips), исправлены недопустимые роли состояний, добавлен реальный интеграционный тест.",
36
+ "pt": "Correção: conformidade com o verificador do repositório - adicionada estrutura de objetos intermediários ausente (canais charging/consumption/pictures/trips), corrigidas funções de estado inválidas, adicionado teste de integração real.",
37
+ "nl": "Fix: naleving van de repository-checker - ontbrekende tussenliggende objectstructuur toegevoegd (charging/consumption/pictures/trips-kanalen), ongeldige statusrollen gecorrigeerd, echte integratietest toegevoegd.",
38
+ "fr": "Correction : conformité au vérificateur de dépôt - ajout de la structure d'objets intermédiaires manquante (canaux charging/consumption/pictures/trips), correction des rôles d'état invalides, ajout d'un véritable test d'intégration.",
39
+ "it": "Correzione: conformità al controllo del repository - aggiunta la struttura di oggetti intermedi mancante (canali charging/consumption/pictures/trips), corretti i ruoli di stato non validi, aggiunto un vero test di integrazione.",
40
+ "es": "Corrección: cumplimiento del verificador del repositorio - se añadió la estructura de objetos intermedios faltante (canales charging/consumption/pictures/trips), se corrigieron roles de estado inválidos, se añadió una prueba de integración real.",
41
+ "pl": "Poprawka: zgodność z weryfikatorem repozytorium - dodano brakującą strukturę obiektów pośrednich (kanały charging/consumption/pictures/trips), poprawiono nieprawidłowe role stanów, dodano rzeczywisty test integracyjny.",
42
+ "uk": "Виправлення: відповідність перевірці репозиторію - додано відсутню проміжну структуру об'єктів (канали charging/consumption/pictures/trips), виправлено недійсні ролі станів, додано реальний інтеграційний тест.",
43
+ "zh-cn": "修复:符合仓库检查器规范 - 添加了缺失的中间对象结构(charging/consumption/pictures/trips 通道),修正了无效的状态角色,添加了真实的集成测试。"
18
44
  },
19
45
  "0.5.7": {
20
46
  "en": "New: Trips tab showing daily kilometers with individual detected trips. Fix: trip detection now backfills kilometers driven before the trip was first detected (5-minute polling gap).",
@@ -67,32 +93,6 @@
67
93
  "pl": "Nowość: standardowy zestaw testów package.test.js z @iobroker/testing",
68
94
  "uk": "Нове: стандартний набір тестів package.test.js з використанням @iobroker/testing",
69
95
  "zh-cn": "新增:使用 @iobroker/testing 的标准测试套件 package.test.js"
70
- },
71
- "0.5.2": {
72
- "en": "Fix: complete translations for changelog entries",
73
- "de": "Fix: vollständige Übersetzungen für Changelog-Einträge",
74
- "ru": "Исправление: полные переводы для записей журнала изменений",
75
- "pt": "Correção: traduções completas para entradas do changelog",
76
- "nl": "Fix: volledige vertalingen voor changelog-items",
77
- "fr": "Correction : traductions complètes pour les entrées du changelog",
78
- "it": "Correzione: traduzioni complete per le voci del changelog",
79
- "es": "Corrección: traducciones completas para las entradas del changelog",
80
- "pl": "Poprawka: kompletne tłumaczenia dla wpisów dziennika zmian",
81
- "uk": "Виправлення: повні переклади для записів журналу змін",
82
- "zh-cn": "修复:完整的更新日志条目翻译"
83
- },
84
- "0.5.1": {
85
- "en": "Fix: use window.setTimeout/setInterval in admin-tab frontend to satisfy repository checker\nMaintenance: dependency cleanup",
86
- "de": "Fix: window.setTimeout/setInterval im Admin-Tab-Frontend verwendet, um den Repository-Checker zu erfüllen\nWartung: Abhängigkeiten bereinigt",
87
- "ru": "Исправление: использование window.setTimeout/setInterval в интерфейсе admin-tab\nОбслуживание: очистка зависимостей",
88
- "pt": "Correção: uso de window.setTimeout/setInterval no frontend admin-tab\nManutenção: limpeza de dependências",
89
- "nl": "Fix: window.setTimeout/setInterval gebruikt in admin-tab frontend\nOnderhoud: dependency opschoning",
90
- "fr": "Correction : utilisation de window.setTimeout/setInterval dans le frontend admin-tab\nMaintenance : nettoyage des dépendances",
91
- "it": "Correzione: utilizzo di window.setTimeout/setInterval nel frontend admin-tab\nManutenzione: pulizia delle dipendenze",
92
- "es": "Corrección: uso de window.setTimeout/setInterval en el frontend admin-tab\nMantenimiento: limpieza de dependencias",
93
- "pl": "Poprawka: użycie window.setTimeout/setInterval w interfejsie admin-tab\nUtrzymanie: czyszczenie zależności",
94
- "uk": "Виправлення: використання window.setTimeout/setInterval у фронтенді admin-tab\nОбслуговування: очищення залежностей",
95
- "zh-cn": "修复:在 admin-tab 前端使用 window.setTimeout/setInterval\n维护:清理依赖项"
96
96
  }
97
97
  },
98
98
  "titleLang": {
@@ -143,7 +143,7 @@
143
143
  "tier": 3,
144
144
  "mode": "daemon",
145
145
  "type": "vehicle",
146
- "compact": false,
146
+ "compact": true,
147
147
  "connectionType": "cloud",
148
148
  "dataSource": "poll",
149
149
  "adminUI": {
@@ -1,11 +1,34 @@
1
1
  'use strict';
2
2
  Object.defineProperty(exports,"__esModule",{value:true});
3
- const crypto=require('crypto');
4
- const https=require('https');
3
+ const crypto=require('node:crypto');
4
+ const https=require('node:https');
5
5
  const forge=require('node-forge');
6
6
  const axios=require('axios');
7
7
  const {deriveAccountP12Password,deriveSignKey,deriveSessionDeviceId,encryptOperatePassword,buildLoginHeaders,buildSignedHeaders,buildRemoteCtlWriteHeaders,buildRemoteCtlWriteHeadersWithoutPin,buildRemoteCtlResultHeaders,buildOperpwdVerifyHeaders}=require('./leapmotor-crypto');
8
8
  const KNOWN_PASSWORDS=['','leapmotor','leap123'];
9
+
10
+ // The vehicle status endpoint path segment does not always match the
11
+ // vehicle's own carType 1:1. Models that share the same underlying
12
+ // platform/backend as another model (e.g. B10 sits on the same LEAP
13
+ // platform family as the C10) use that other model's endpoint segment
14
+ // instead of their own name. CONFIRMED for B10->c10 via a real B10 owner
15
+ // running probe-status-endpoint.js (2026-07): the "c10" segment returned
16
+ // real vehicle data (GPS/signal values), not just a generic 200 response.
17
+ // Unmapped models fall back to their own carType, lowercased (this is
18
+ // what already works for T03).
19
+ const STATUS_ENDPOINT_OVERRIDES={
20
+ B10:'c10',
21
+ // B05, C16 are suspected to share the same C10-family endpoint but this
22
+ // is UNCONFIRMED - add/adjust here once verified by an owner via
23
+ // probe-status-endpoint.js.
24
+ };
25
+
26
+ function mapCarTypeToStatusEndpoint(carType){
27
+ const ct=String(carType||'').trim();
28
+ const override=STATUS_ENDPOINT_OVERRIDES[ct.toUpperCase()];
29
+ return (override||ct).toLowerCase();
30
+ }
31
+
9
32
  class LeapmotorClient{
10
33
  constructor(config){
11
34
  this.userId=null;this.token=null;this.signIkm=null;this.signSalt=null;this.signInfo=null;
@@ -17,6 +40,10 @@ class LeapmotorClient{
17
40
  this.appKeyPem=config.appKeyPem;
18
41
  this.http=this._createHttpClient(config.appCertPem,config.appKeyPem);
19
42
  }
43
+ // NOTE: rejectUnauthorized is intentionally false here. The Leapmotor cloud API uses a
44
+ // client-certificate (mTLS) based authentication scheme with a non-standard/internal CA
45
+ // chain for its server certificate that is not part of the public trust store, so standard
46
+ // certificate validation cannot succeed against this specific first-party endpoint.
20
47
  _createHttpClient(certPem,keyPem){const agent=new https.Agent({cert:certPem,key:keyPem,rejectUnauthorized:false});return axios.create({baseURL:this.config.baseUrl,timeout:this.config.timeout,httpsAgent:agent,headers:{'Content-Type':'application/x-www-form-urlencoded'}})}
21
48
  get _signKey(){if(!this.signIkm)throw new Error('Not authenticated');return Buffer.from(deriveSignKey(this.signIkm,this.signSalt,this.signInfo))}
22
49
  _authHeaders(){if(!this.userId||!this.token)throw new Error('Not authenticated');return{userId:this.userId,token:this.token}}
@@ -63,7 +90,7 @@ class LeapmotorClient{
63
90
  }));
64
91
  }
65
92
  async getVehicleStatus(vehicle){
66
- const ct=vehicle.carType.trim().toLowerCase();
93
+ const ct=mapCarTypeToStatusEndpoint(vehicle.carType);
67
94
  const h={...this._h(buildSignedHeaders({signKey:this._signKey,deviceId:this.deviceId,vin:vehicle.vin,language:this.config.language})),...this._authHeaders()};
68
95
  const resp=await this.http.post(`/carownerservice/oversea/vehicle/v1/status/get/${ct}`,`vin=${encodeURIComponent(vehicle.vin)}`,{headers:h});
69
96
  return this._parseResponse(resp.data,'vehicle status').data||{};
@@ -115,7 +142,7 @@ class LeapmotorClient{
115
142
  return this._parseResponse(resp.data,'mileage energy');
116
143
  }
117
144
  async getConsumptionWeeklyRank(vehicle){
118
- const crypto=require('crypto');
145
+ const crypto=require('node:crypto');
119
146
  const n=String(Math.floor(Math.random()*9900000+100000));
120
147
  const ts=String(Date.now());
121
148
  const lang=this.config.language||'en-GB';
@@ -128,7 +155,7 @@ class LeapmotorClient{
128
155
  return this._parseResponse(resp.data,'consumption weekly');
129
156
  }
130
157
  async getCarPictureKey(vehicle){
131
- const crypto=require('crypto');
158
+ const crypto=require('node:crypto');
132
159
  const n=String(Math.floor(Math.random()*9900000+100000));
133
160
  const ts=String(Date.now());
134
161
  const lang=this.config.language||'en-GB';
@@ -141,8 +168,8 @@ class LeapmotorClient{
141
168
  return this._parseResponse(resp.data,'car picture key');
142
169
  }
143
170
  async downloadCarPictureZip(key){
144
- const crypto=require('crypto');
145
- const https=require('https');
171
+ const crypto=require('node:crypto');
172
+ const https=require('node:https');
146
173
  const n=String(Math.floor(Math.random()*9900000+100000));
147
174
  const ts=String(Date.now());
148
175
  const lang=this.config.language||'en-GB';
@@ -180,7 +207,7 @@ class LeapmotorClient{
180
207
  const deadline=Date.now()+Math.max(Number(rd.queryRemoteCtlResultTimeout||30000),1000);
181
208
  const interval=Number(rd.queryInterval||2000);
182
209
  while(Date.now()<deadline){
183
- await new Promise(r=>{if(this._adapter&&this._adapter.setTimeout)this._adapter.setTimeout(r,interval);else setTimeout(r,interval);});
210
+ await new Promise(r=>this._adapter.setTimeout(r,interval));
184
211
  const h={...this._h(buildRemoteCtlResultHeaders({signKey:this._signKey,deviceId:this.deviceId,remoteCtlId:id,language:this.config.language})),...this._authHeaders()};
185
212
  const resp=await this.http.post('/carownerservice/oversea/vehicle/v1/app/remote/ctl/result/query',`remoteCtlId=${encodeURIComponent(id)}`,{headers:h});
186
213
  if(this._parseResponse(resp.data,'remote poll').data===1)return;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  Object.defineProperty(exports,"__esModule",{value:true});
3
- const crypto=require('crypto');
3
+ const crypto=require('node:crypto');
4
4
  const SM4_SBOX=new Uint8Array([0xD6,0x90,0xE9,0xFE,0xCC,0xE1,0x3D,0xB7,0x16,0xB6,0x14,0xC2,0x28,0xFB,0x2C,0x05,0x2B,0x67,0x9A,0x76,0x2A,0xBE,0x04,0xC3,0xAA,0x44,0x13,0x26,0x49,0x86,0x06,0x99,0x9C,0x42,0x50,0xF4,0x91,0xEF,0x98,0x7A,0x33,0x54,0x0B,0x43,0xED,0xCF,0xAC,0x62,0xE4,0xB3,0x1C,0xA9,0xC9,0x08,0xE8,0x95,0x80,0xDF,0x94,0xFA,0x75,0x8F,0x3F,0xA6,0x47,0x07,0xA7,0xFC,0xF3,0x73,0x17,0xBA,0x83,0x59,0x3C,0x19,0xE6,0x85,0x4F,0xA8,0x68,0x6B,0x81,0xB2,0x71,0x64,0xDA,0x8B,0xF8,0xEB,0x0F,0x4B,0x70,0x56,0x9D,0x35,0x1E,0x24,0x0E,0x5E,0x63,0x58,0xD1,0xA2,0x25,0x22,0x7C,0x3B,0x01,0x21,0x78,0x87,0xD4,0x00,0x46,0x57,0x9F,0xD3,0x27,0x52,0x4C,0x36,0x02,0xE7,0xA0,0xC4,0xC8,0x9E,0xEA,0xBF,0x8A,0xD2,0x40,0xC7,0x38,0xB5,0xA3,0xF7,0xF2,0xCE,0xF9,0x61,0x15,0xA1,0xE0,0xAE,0x5D,0xA4,0x9B,0x34,0x1A,0x55,0xAD,0x93,0x32,0x30,0xF5,0x8C,0xB1,0xE3,0x1D,0xF6,0xE2,0x2E,0x82,0x66,0xCA,0x60,0xC0,0x29,0x23,0xAB,0x0D,0x53,0x4E,0x6F,0xD5,0xDB,0x37,0x45,0xDE,0xFD,0x8E,0x2F,0x03,0xFF,0x6A,0x72,0x6D,0x6C,0x5B,0x51,0x8D,0x1B,0xAF,0x92,0xBB,0xDD,0xBC,0x7F,0x11,0xD9,0x5C,0x41,0x1F,0x10,0x5A,0xD8,0x0A,0xC1,0x31,0x88,0xA5,0xCD,0x7B,0xBD,0x2D,0x74,0xD0,0x12,0xB8,0xE5,0xB4,0xB0,0x89,0x69,0x97,0x4A,0x0C,0x96,0x77,0x7E,0x65,0xB9,0xF1,0x09,0xC5,0x6E,0xC6,0x84,0x18,0xF0,0x7D,0xEC,0x3A,0xDC,0x4D,0x20,0x79,0xEE,0x5F,0x3E,0xD7,0xCB,0x39,0x48]);
5
5
  const RK=new Uint32Array([0x818FA553,0xEBA3318D,0x5FC3C93A,0xBD1DADD9,0xBB61CAB9,0x000FD7EA,0xDC6E0166,0xDA937279,0x607EE786,0xB548754C,0x107330E4,0xEA17C186,0x0F56F74B,0xB21E443C,0xE1210FE2,0x009995C8,0xE7529A48,0x6EF474F6,0x2AB06DF6,0x43B11BE8,0x359D4A14,0xC29E2CDE,0x30CF6A3E,0x79D1C806,0x7C502387,0xAAAB9BC6,0xF0FE744B,0x1CAFC872,0x95A9D075,0x88070D58,0x22800475,0x8391938B]);
6
6
  function rl(v,b){return((v<<b)|(v>>>(32-b)))>>>0}