bt-sensors-plugin-sk 1.2.5 → 1.2.6-beta-1

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.
Files changed (126) hide show
  1. package/.vscode/settings.json +2 -0
  2. package/BTSensor.js +77 -38
  3. package/DistanceManager.js +249 -0
  4. package/Mixin.js +19 -0
  5. package/OutOfRangeDevice.js +46 -0
  6. package/README.md +26 -6
  7. package/classLoader.js +13 -8
  8. package/connectUUID.exp +26 -0
  9. package/development/FakeBTDevice.js +57 -0
  10. package/development/package.json +5 -0
  11. package/diff.txt +2860 -0
  12. package/index.js +58 -12
  13. package/package.json +8 -6
  14. package/public/698.js +14 -0
  15. package/public/847.js +1 -1
  16. package/public/images/ATC.jpeg +0 -0
  17. package/public/images/Aranet4.webp +0 -0
  18. package/public/images/BP108B.webp +0 -0
  19. package/public/images/GoveeH5074.jpg +0 -0
  20. package/public/images/GoveeH5075.webp +0 -0
  21. package/public/images/GoveeH510x.jpg +0 -0
  22. package/public/images/InkbirdTH3.webp +0 -0
  23. package/public/images/JBDBMS.webp +0 -0
  24. package/public/images/Junctek.webp +0 -0
  25. package/public/images/KilovaultHLXPlus.jpg +0 -0
  26. package/public/images/LancolVoltageMeter.webp +0 -0
  27. package/public/images/LiTimeLiFePo4Battery.avif +0 -0
  28. package/public/images/MercurySmartcraft.jpg +0 -0
  29. package/public/images/MopekaTankSensor.jpg +0 -0
  30. package/public/images/RemoranWave3.jpeg +0 -0
  31. package/public/images/RenogyInverter.jpg +0 -0
  32. package/public/images/RenogyRoverClient.jpg +0 -0
  33. package/public/images/RenogySmartLiFePo4Battery.webp +0 -0
  34. package/public/images/RuuviTag.jpg +0 -0
  35. package/public/images/ShellyBLUHT.webp +0 -0
  36. package/public/images/ShellyBLUMotion.webp +0 -0
  37. package/public/images/ShellyBluDoorWindow.webp +0 -0
  38. package/public/images/Skanbatt.jpg +0 -0
  39. package/public/images/SmartBatteryProtect.webp +0 -0
  40. package/public/images/SmartBatterySense.webp +0 -0
  41. package/public/images/SwitchBotMeterPlus.webp +0 -0
  42. package/public/images/SwitchBotTH.webp +0 -0
  43. package/public/images/TopbandBattery.webp +0 -0
  44. package/public/images/Ultrasonic.jpg +0 -0
  45. package/public/images/VictronBlueSmartACCharger.jpg +0 -0
  46. package/public/images/VictronBlueSolarMPPT.jpeg +0 -0
  47. package/public/images/VictronCerboGX.webp +0 -0
  48. package/public/images/VictronInverterRS.webp +0 -0
  49. package/public/images/VictronLynxSmartBMS.webp +0 -0
  50. package/public/images/VictronMultiPlus-II.webp +0 -0
  51. package/public/images/VictronOrionTrIsolated.webp +0 -0
  52. package/public/images/VictronOrionTrNonIsolated.webp +0 -0
  53. package/public/images/VictronPhoenixInverter.webp +0 -0
  54. package/public/images/VictronPhoenixSmart1600.webp +0 -0
  55. package/public/images/VictronSmartBatteryProtect.jpg +0 -0
  56. package/public/images/VictronSmartIP43.webp +0 -0
  57. package/public/images/VictronSmartLithiumBattery.jpg +0 -0
  58. package/public/images/VictronSmartSolarMPPT.webp +0 -0
  59. package/public/images/VictronVEBus.webp +0 -0
  60. package/public/images/eco-worthy.webp +0 -0
  61. package/public/images/iBeacon.jpg +0 -0
  62. package/public/remoteEntry.js +1 -1
  63. package/readUUID.exp +23 -0
  64. package/sensor_classes/ATC.js +3 -2
  65. package/sensor_classes/Aranet2.js +3 -1
  66. package/sensor_classes/Aranet4.js +1 -2
  67. package/sensor_classes/BankManager.js +1 -1
  68. package/sensor_classes/Beacon/AbstractBeaconMixin.js +85 -0
  69. package/sensor_classes/Beacon/Eddystone.js +77 -0
  70. package/sensor_classes/Beacon/iBeacon.js +58 -0
  71. package/sensor_classes/EcoWorthy.js +160 -0
  72. package/sensor_classes/EctiveBMS.js +269 -0
  73. package/sensor_classes/FeasyComBeacon.js +68 -0
  74. package/sensor_classes/GobiusCTankMeter.js +4 -3
  75. package/sensor_classes/GoveeH5074.js +2 -0
  76. package/sensor_classes/GoveeH5075.js +2 -0
  77. package/sensor_classes/GoveeH510x.js +1 -0
  78. package/sensor_classes/Inkbird.js +1 -0
  79. package/sensor_classes/JBDBMS.js +1 -0
  80. package/sensor_classes/Junctek.js +14 -6
  81. package/sensor_classes/KilovaultHLXPlus.js +1 -0
  82. package/sensor_classes/LancolVoltageMeter.js +2 -0
  83. package/sensor_classes/MercurySmartcraft.js +1 -0
  84. package/sensor_classes/MopekaTankSensor.js +7 -204
  85. package/sensor_classes/RemoranWave3.js +2 -0
  86. package/sensor_classes/Renogy/RenogySensor.js +1 -0
  87. package/sensor_classes/RenogyBattery.js +3 -4
  88. package/sensor_classes/RenogyInverter.js +3 -6
  89. package/sensor_classes/RenogyRoverClient.js +3 -0
  90. package/sensor_classes/RuuviTag.js +11 -8
  91. package/sensor_classes/ShellySBDW002C.js +3 -1
  92. package/sensor_classes/ShellySBHT003C.js +7 -0
  93. package/sensor_classes/ShellySBMO003Z.js +3 -2
  94. package/sensor_classes/ShenzhenLiOnBMS.js +4 -0
  95. package/sensor_classes/SwitchBotMeterPlus.js +1 -1
  96. package/sensor_classes/SwitchBotTH.js +2 -1
  97. package/sensor_classes/UNKNOWN.js +2 -1
  98. package/sensor_classes/UltrasonicWindMeter.js +3 -0
  99. package/sensor_classes/Victron/VictronConstants.js +2 -0
  100. package/sensor_classes/Victron/VictronIdentifier.js +24 -0
  101. package/sensor_classes/Victron/VictronSensor.js +59 -49
  102. package/sensor_classes/VictronACCharger.js +1 -6
  103. package/sensor_classes/VictronBatteryMonitor.js +39 -28
  104. package/sensor_classes/VictronDCDCConverter.js +1 -4
  105. package/sensor_classes/VictronDCEnergyMeter.js +1 -4
  106. package/sensor_classes/VictronGXDevice.js +1 -4
  107. package/sensor_classes/VictronInverter.js +2 -3
  108. package/sensor_classes/VictronInverterRS.js +2 -4
  109. package/sensor_classes/VictronLynxSmartBMS.js +1 -4
  110. package/sensor_classes/VictronOrionXS.js +1 -3
  111. package/sensor_classes/VictronSmartBatteryProtect.js +1 -4
  112. package/sensor_classes/VictronSmartLithium.js +1 -4
  113. package/sensor_classes/VictronSolarCharger.js +1 -3
  114. package/sensor_classes/VictronVEBus.js +1 -4
  115. package/sensor_classes/XiaomiMiBeacon.js +5 -2
  116. package/sensor_classes/iBeaconSensor.js +40 -0
  117. package/src/components/PluginConfigurationPanel.js +179 -184
  118. package/test.txt +805 -0
  119. package/public/681.js +0 -14
  120. package/sensor_classes/IBeacon.js +0 -45
  121. /package/public/{681.js.LICENSE.txt → 698.js.LICENSE.txt} +0 -0
  122. /package/public/images/{Aranet2_HOME_F_900x900_90OVA5J.original.webp → Aranet2.webp} +0 -0
  123. /package/public/images/{Bank Manager All-in-onewc.webp → BankManager.webp} +0 -0
  124. /package/public/images/{Gobius_C.png → GobiusCTankMeter.png} +0 -0
  125. /package/public/images/{Victron-SmartShunt.jpg → VictronSmartShunt.jpg} +0 -0
  126. /package/public/images/{smartsolarMPPT7515.png → VictronSmartSolarMPPT7515.png} +0 -0
@@ -1,11 +1,10 @@
1
1
  import Form from '@rjsf/core' ;
2
2
  import validator from '@rjsf/validator-ajv8';
3
- import React from "react";
4
3
  import ReactHtmlParser from 'react-html-parser';
5
-
4
+ import React from 'react'
6
5
  import {useEffect, useState} from 'react'
7
6
 
8
- import {Button, Grid } from '@material-ui/core';
7
+ import {Button, Grid, Snackbar } from '@material-ui/core';
9
8
  import { makeStyles } from '@material-ui/core/styles';
10
9
 
11
10
  import { SignalCellular0Bar, SignalCellular1Bar, SignalCellular2Bar, SignalCellular3Bar, SignalCellular4Bar, SignalCellularConnectedNoInternet0Bar } from '@material-ui/icons';
@@ -20,13 +19,14 @@ import { ListGroupItem } from 'react-bootstrap';
20
19
 
21
20
  import ProgressBar from 'react-bootstrap/ProgressBar';
22
21
 
23
- var _sensorMap, _sensorDomains={}, _sensorList={}
24
-
25
- export default function BTConfig (props) {
22
+ export function BTConfig (props) {
26
23
 
27
24
  const _uiSchema= {
28
25
  "ui:options": {label: false},
29
- 'title': { 'ui:widget': 'hidden' }
26
+ "paths":{
27
+ enableMarkdownInDescription:true
28
+ },
29
+ 'title': { 'ui:widget': 'hidden' },
30
30
  }
31
31
 
32
32
  const baseUISchema =
@@ -71,10 +71,12 @@ const useStyles = makeStyles((theme) => ({
71
71
 
72
72
  const [schema, setSchema] = useState({})
73
73
  const [ uiSchema, setUISchema] = useState(_uiSchema )
74
- const [sensorList, setSensorList] = useState([])
75
74
 
76
75
  const [sensorData, setSensorData] = useState()
77
- const [sensorMap, setSensorMap ] = useState(new Map() )
76
+ const [sensorClassChanged, setSensorClassChanged] = useState(false)
77
+
78
+ const [enableSchema, setEnableSchema] = useState(true)
79
+ const [sensorMap, setSensorMap ] = useState(new Map())
78
80
 
79
81
  const [progress, setProgress ] = useState({
80
82
  "progress":0, "maxTimeout": 100,
@@ -84,13 +86,14 @@ const useStyles = makeStyles((theme) => ({
84
86
 
85
87
  const [pluginState, setPluginState ] = useState("unknown")
86
88
  const [error, setError ] = useState()
89
+ const [snackbarOpen, setSnackbarOpen] = useState(false)
90
+ const [snackbarMessage, setSnackbarMessage] = useState("")
87
91
  const classes = useStyles();
88
92
 
93
+
89
94
 
90
95
  function sendJSONData(cmd, data){
91
96
 
92
- console.log(`sending ${cmd}`)
93
- console.log(data)
94
97
  const headers = new Headers();
95
98
  headers.append("Content-Type", "application/json");
96
99
  return fetch(`/plugins/bt-sensors-plugin-sk/${cmd}`, {
@@ -100,91 +103,85 @@ const useStyles = makeStyles((theme) => ({
100
103
  headers:headers
101
104
  })
102
105
  }
103
-
104
- async function fetchJSONData(path){
105
- console.log(`fetching ${path}`)
106
- var result
107
- try {
108
- result = fetch(`/plugins/bt-sensors-plugin-sk/${path}`, {
109
- credentials: 'include'
110
- })
111
- } catch (e) {
112
- result=
113
- {
114
- status: 500,
115
- statusText: e.toString()
116
- }
117
- }
118
- return result
106
+ async function fetchJSONData(path, data = {}) {
107
+ let result;
108
+ try {
109
+ // Convert data object to query string
110
+ const query = Object.keys(data).length
111
+ ? '?' + new URLSearchParams(data).toString()
112
+ : '';
113
+ result = await fetch(`/plugins/bt-sensors-plugin-sk/${path}${query}`, {
114
+ credentials: 'include',
115
+ method: 'GET'
116
+ });
117
+ } catch (e) {
118
+ result = {
119
+ status: 500,
120
+ statusText: e.toString()
121
+ };
119
122
  }
120
-
123
+ return result;
124
+ }
121
125
  async function getSensors(){
122
- console.log("getSensors")
123
126
  const response = await fetchJSONData("getSensors")
124
127
  if (response.status!=200){
125
128
  throw new Error(`Unable get sensor data: ${response.statusText} (${response.status}) `)
126
129
  }
127
130
  const json = await response.json()
128
- console.log(json)
129
- //for (let i=0;i<json.length;i++){
130
- // json[i].schema.htmlDescription=<div>{ReactHtmlParser(json[i].schema.htmlDescription)}<p></p></div>
131
- //}
131
+
132
132
  return json
133
133
 
134
134
  }
135
- async function getDomains(){
136
- console.log("getDomains")
137
- const response = await fetchJSONData("getDomains")
135
+
136
+
137
+ async function getSensorInfo(mac, sensorClass){
138
+
139
+ const response = await fetchJSONData("getSensorInfo",{mac_address: mac, class: sensorClass})
138
140
  if (response.status!=200){
139
- throw new Error(`Unable get domain data: ${response.statusText} (${response.status}) `)
141
+ debugger
142
+ throw new Error(`Unable get sensor info: ${response.statusText} (${response.status}) `)
140
143
  }
141
144
  const json = await response.json()
142
- console.log(json)
143
145
  return json
144
-
145
146
  }
147
+
146
148
  async function getBaseData(){
147
- console.log("getBaseData")
148
149
  const response = await fetchJSONData("getBaseData")
149
150
  if (response.status!=200){
150
151
  throw new Error(`Unable to get base data: ${response.statusText} (${response.status}) `)
151
152
  }
152
153
  const json = await response.json()
153
- console.log(json)
154
154
  json.schema.htmlDescription=<div>{ReactHtmlParser(json.schema.htmlDescription)}<p></p></div>
155
155
  return json
156
156
  }
157
+
157
158
  async function getProgress(){
158
- console.log("getProgress")
159
159
  const response = await fetchJSONData("getProgress")
160
160
  if (response.status!=200){
161
161
  throw new Error(`Unable to get progress: ${response.statusText} (${response.status}) `)
162
162
  }
163
163
  const json = await response.json()
164
- console.log(json)
165
164
  return json
166
165
  }
167
166
 
168
167
  function updateSensorData(data){
169
- console.log("updateSensorData")
170
168
  sendJSONData("updateSensorData", data).then((response)=>{
171
169
  if (response.status != 200) {
172
170
  throw new Error(response.statusText)
173
171
  }
174
- sensorMap.get(data.mac_address)._changesMade=false
175
- sensorMap.get(data.mac_address).config = data
176
-
172
+ setSensorMap((sm)=>{sm.delete(data.mac_address); return new Map(sm) })
173
+ setSchema( {} )
174
+
177
175
  })
178
176
  }
179
177
 
180
178
  function undoChanges(mac) {
181
- console.log("undoChanges")
182
179
  sensorMap.get(mac)._changesMade = false
180
+ sensorMap.get(mac).config = JSON.parse(JSON.stringify(sensorMap.get(mac).configCopy))
183
181
  setSensorData( sensorMap.get(mac).config )
184
182
  }
185
183
 
186
184
  function removeSensorData(mac){
187
- console.log("removeSensorData")
188
185
 
189
186
  try{
190
187
 
@@ -193,131 +190,151 @@ const useStyles = makeStyles((theme) => ({
193
190
  throw new Error(response.statusText)
194
191
  }
195
192
  })
196
-
197
- _sensorMap.delete(mac)
198
-
199
- setSensorMap(new Map(_sensorMap))
193
+ setSensorMap((sm)=>{sm.delete(mac); return new Map(sm) })
200
194
  setSchema( {} )
201
195
  } catch {(e)=>
202
- setError( new Error(`Couldn't remove ${mac}: ${e}`))
196
+ setError( `Couldn't remove ${mac}: ${e}`)
203
197
  }
204
198
 
205
199
  }
206
200
 
207
201
 
208
202
  function updateBaseData(data){
209
- console.log("updateBaseData")
210
-
203
+ setSensorMap(new Map())
204
+ //setSensorList({})
211
205
  sendJSONData("updateBaseData", data).then( (response )=>{
212
206
  if (response.status != 200) {
213
- setError(new Error(`Unable to update base data: ${response.statusText} (${response.status})`))
214
- } /*else {
215
- getProgress().then((json)=>{
216
- setProgress(json)
217
- }).catch((e)=>{
218
- setError(e)
219
- })
220
- }*/
207
+ setError(`Unable to update base data: ${response.statusText} (${response.status})`)
208
+ }
221
209
  })
222
- }
223
-
224
210
 
225
- function refreshSensors(){
226
- console.log('refreshing sensor map')
227
-
228
- getSensors().then((sensors)=>{
229
- setSensorMap (new Map(sensors.map((sensor)=>[sensor.info.mac,sensor])));
230
- })
231
- .catch((e)=>{
232
- setError(e)
233
- })
234
211
  }
235
212
 
236
-
237
213
  useEffect(()=>{
238
- console.log("useEffect([])")
239
214
  let eventSource=null
240
-
241
215
  fetchJSONData("getPluginState").then( async (response)=> {
216
+
217
+ function newSensorEvent(event){
218
+ let json = JSON.parse(event.data)
219
+ console.log(`New sensor: ${json.info.mac}`)
220
+ setSensorMap( (_sm)=> {
221
+ //if (!_sm.has(json.info.mac))
222
+ _sm.set(json.info.mac, json)
223
+
224
+ return new Map(_sm)
225
+ }
226
+ )
227
+ }
228
+ function sensorChangedEvent(event){
229
+ console.log("sensorchanged")
230
+ const json = JSON.parse(event.data)
231
+
232
+ setSensorMap( (_sm) => {
233
+ const sensor = _sm.get(json.mac)
234
+ if (sensor)
235
+ Object.assign(sensor.info, json )
236
+ return new Map(_sm)
237
+ })
238
+ }
239
+
240
+
242
241
  if (response.status==404) {
243
242
  setPluginState("unknown")
244
243
  throw new Error("unable to get plugin state")
245
244
  }
246
245
  const json = await response.json()
247
- console.log("Setting up eventsource")
248
246
  eventSource = new EventSource("/plugins/bt-sensors-plugin-sk/sse", { withCredentials: true })
249
247
 
250
- setPluginState(json.state)
251
-
252
- _sensorDomains = await getDomains()
253
-
254
248
  eventSource.addEventListener("newsensor", (event) => {
255
- console.log("newsensor")
256
- let json = JSON.parse(event.data)
257
-
258
- if (!_sensorMap.has(json.info.mac)) {
259
- console.log(`New sensor: ${json.info.mac}`)
260
- setSensorMap(new Map(_sensorMap.set(json.info.mac, json)))
261
- }
249
+ newSensorEvent(event)
262
250
  });
263
251
 
264
252
  eventSource.addEventListener("sensorchanged", (event) => {
265
- let json = JSON.parse(event.data)
266
- console.log("sensorchanged")
267
- console.log(json)
268
-
269
- if (_sensorMap.has(json.mac)) {
270
- let sensor = _sensorMap.get(json.mac)
271
-
272
- Object.assign(sensor.info, json )
273
- setSensorMap(new Map ( _sensorMap ))
274
- }
253
+ sensorChangedEvent(event)
275
254
  });
255
+
276
256
  eventSource.addEventListener("progress", (event) => {
277
- console.log("progress")
278
257
  const json = JSON.parse(event.data)
279
258
  setProgress(json)
280
- console.log(json)
281
259
  });
282
260
 
283
261
  eventSource.addEventListener("pluginstate", (event) => {
284
- console.log("pluginstate")
285
262
  const json = JSON.parse(event.data)
286
263
  setPluginState(json.state)
287
264
  });
288
-
289
- })
265
+
266
+ setPluginState(json.state);
290
267
 
268
+ (async ()=>{
269
+ const sensors = await getSensors()
270
+ setSensorMap ( new Map(sensors.map((sensor)=>[sensor.info.mac,sensor])) )
271
+ })()
272
+
273
+ })
291
274
  .catch( (e) => {
292
- setError(e)
275
+ setError(e.message)
293
276
  }
294
277
  )
295
278
  return () => {
296
279
  console.log("Closing connection to SSE")
297
280
  eventSource.close()
298
281
  };
282
+
299
283
  },[])
300
284
 
285
+
286
+ useEffect(()=>{
287
+
288
+ if (!sensorClassChanged) return
289
+ if (!(sensorData && sensorMap) ) return
290
+
291
+ const _sensor = sensorMap.get(sensorData.mac_address)
292
+ if (_sensor && schema && sensorData &&
293
+ Object.hasOwn(sensorData,"params" )){
294
+ if (_sensor.info.class == "UNKNOWN" && sensorData.params.sensorClass && sensorData.params.sensorClass != "UNKNOWN") {
295
+ setEnableSchema(false)
296
+ setSnackbarMessage(`Please wait. Fetching schema for ${sensorData.params.sensorClass}...`)
297
+ getSensorInfo(sensorData.mac_address, sensorData.params.sensorClass).then((json)=>{
298
+ setSchema(json.schema)
299
+ }).catch((e)=>{
300
+ alert(e.message)
301
+ })
302
+ .finally(()=>{
303
+ setSnackbarMessage("")
304
+ setEnableSchema(true)
305
+ setSensorClassChanged(false)
306
+ })
307
+ }
308
+
309
+ }
310
+
311
+ },[sensorClassChanged])
312
+
301
313
  useEffect(()=>{
302
- console.log("useEffect([pluginState])")
303
- if (pluginState=="started"){
304
- refreshSensors()
305
-
314
+ if (snackbarMessage=="")
315
+ setSnackbarOpen(false)
316
+ else {
317
+ setSnackbarOpen(true)
318
+ }
319
+
320
+ },[snackbarMessage])
321
+
322
+ useEffect(()=>{
323
+ if (pluginState=="started") {
306
324
  getBaseData().then((json) => {
307
325
  setBaseSchema(json.schema);
308
326
  setBaseData(json.data);
309
327
  }).catch((e)=>{
310
- setError(e)
328
+ setError(e.message)
311
329
  })
312
330
 
313
331
  getProgress().then((json)=>{
314
332
  setProgress(json)
315
333
  }).catch((e)=>{
316
- setError(e)
334
+ setError(e.message)
317
335
  })
318
336
 
319
337
  } else{
320
- setSensorMap(new Map())
321
338
  setBaseSchema({})
322
339
  setBaseData({})
323
340
  }
@@ -325,9 +342,10 @@ useEffect(()=>{
325
342
  },[pluginState])
326
343
 
327
344
 
328
-
329
345
  function confirmDelete(mac){
330
- const result = window.confirm(`Delete configuration for ${mac}?`)
346
+
347
+ const sensor = sensorMap.get(mac)
348
+ const result = !hasConfig(sensor) || window.confirm(`Delete configuration for ${sensor.info.name}?`)
331
349
  if (result)
332
350
  removeSensorData(mac)
333
351
  }
@@ -352,7 +370,7 @@ function signalStrengthIcon(sensor){
352
370
 
353
371
  }
354
372
  function hasConfig(sensor){
355
- return Object.keys(sensor.config).length>0;
373
+ return Object.keys(sensor.configCopy).length>0;
356
374
  }
357
375
 
358
376
  function createListGroupItem(sensor){
@@ -376,66 +394,43 @@ function createListGroupItem(sensor){
376
394
  </ListGroupItem>
377
395
  }
378
396
 
379
- function configuredDevices(){
380
- return Array.from(sensorMap.entries()).filter((entry)=>hasConfig(entry[1]))
381
- }
382
397
 
383
398
  function devicesInDomain(domain){
384
- if (domain==="_configured")
385
- return configuredDevices()
386
- else
399
+
387
400
  return Array.from(sensorMap.entries()).filter((entry)=>entry[1].info.domain===domain)
388
401
  }
389
402
 
403
+ function ifNullNaN(value){
404
+ return value==null? NaN : value
405
+ }
390
406
 
391
- useEffect(()=>{
392
- console.log("useEffect([sensorMap])")
393
-
394
- _sensorMap = sensorMap
395
-
396
- const _sensorDomains = [... (new Set(sensorMap.entries().map((entry)=>{ return entry[1].info.domain})))].sort()
397
- const sl = {
398
- _configured: configuredDevices().length==0?
407
+ function getTabs(){
408
+ const sensorDomains = [... (new Set(sensorMap.entries().map((entry)=>{ return entry[1].info.domain})))].sort()
409
+ const cd = Array.from(sensorMap.entries()).filter((entry)=>hasConfig(entry[1]))
410
+ let sensorList={}
411
+ sensorList["_configured"]=
412
+ cd.length==0?
399
413
  "Select a device from its domain tab (Electrical etc.) and configure it.":
400
- configuredDevices().map((entry) => {
414
+ cd.map((entry) => {
401
415
  return createListGroupItem(sensorMap.get(entry[0]))
402
416
  })
403
- }
404
-
405
- _sensorDomains.forEach((d)=>{
406
- sl[d]=devicesInDomain(d).map((entry) => {
417
+
418
+ sensorDomains.forEach((d)=>{
419
+ sensorList[d]=devicesInDomain(d).map((entry) => {
407
420
  return createListGroupItem(sensorMap.get(entry[0]))
408
421
  })
409
- })
410
- _sensorList=sl
411
-
412
-
413
- },[sensorMap]
414
- )
415
-
416
- function ifNullNaN(value){
417
- return value==null? NaN : value
418
- }
419
-
420
- function getSensorList(domain){
421
- return _sensorList[domain]
422
- }
423
-
424
- function getTabs(){
422
+ })
425
423
 
426
- return Object.keys(_sensorList).map((domain)=> {return getTab(domain)})
424
+ return Object.keys(sensorList).map((domain)=> {return getTab(domain, sensorList[domain])})
427
425
  }
428
- // <div style={{paddingBottom: 20}} class="d-flex flex-wrap justify-content-start align-items-start">
429
- // <div class="d-flex flex-column" >
430
426
 
431
- function getTab(key){
432
- var title = key.slice(key.charAt(0)==="_"?1:0)
433
- let sl = getSensorList(key)
427
+ function getTab(key, sensorList){
428
+ let title = key.slice(key.charAt(0)==="_"?1:0)
434
429
 
435
- return <Tab eventKey={key} title={`${title.charAt(0).toUpperCase()}${title.slice(1)}${devicesInDomain(key).length==0?'':' ('+devicesInDomain(key).length+')'}` } >
430
+ return <Tab eventKey={key} title={`${title.charAt(0).toUpperCase()}${title.slice(1)}${typeof sensorList=='string'?'':' ('+sensorList.length+')'}` } >
436
431
 
437
432
  <ListGroup style={{ maxHeight: '300px', overflowY: 'auto' }}>
438
- {sl}
433
+ {sensorList}
439
434
  </ListGroup>
440
435
 
441
436
 
@@ -447,22 +442,6 @@ useEffect(()=>{
447
442
  window.open(url, "_blank", "noreferrer");
448
443
  }
449
444
 
450
- function CustomFieldTemplate(props) {
451
- const { id, classNames, style, label, help, required, description, errors, children } = props;
452
- return (
453
- <div className={classNames} style={style}>
454
- <Grid container xs={12} direction="row" spacing="1">
455
- <Grid item xs={1} sm container direction="column">
456
- <Grid item ><label htmlFor={id}>{label}{required ? '*' : null}</label></Grid>
457
- <Grid item> {description}</Grid>
458
- </Grid>
459
- <Grid item>{children}</Grid>
460
- </Grid>
461
- {errors}
462
- {help}
463
- </div>
464
- );
465
- }
466
445
 
467
446
  if (pluginState=="stopped" || pluginState=="unknown")
468
447
  return (<h3>Enable plugin to see configuration</h3>)
@@ -470,6 +449,14 @@ useEffect(()=>{
470
449
  return(
471
450
 
472
451
  <div>
452
+
453
+ <Snackbar
454
+ anchorOrigin={{ horizontal: 'center', vertical: 'bottom' }}
455
+ onClose={() => setSnackbarOpen(false)}
456
+ open={snackbarOpen}
457
+ message={snackbarMessage}
458
+ key={"snackbar"}
459
+ />
473
460
  <div className={classes.root}>
474
461
 
475
462
  <Button variant="contained" onClick={()=>{openInNewTab("https://github.com/naugehyde/bt-sensors-plugin-sk/tree/1.2.0-beta#configuration")}}>Documentation</Button>
@@ -480,7 +467,7 @@ useEffect(()=>{
480
467
  </div>
481
468
  <hr style={{"width":"100%","height":"1px","color":"gray","background-color":"gray","text-align":"left","margin-left":0}}></hr>
482
469
 
483
- {error?<h2 style="color: red;">{error}</h2>:""}
470
+ {error?<h2 style={{color: 'red'}}>{error}</h2>:""}
484
471
  <Form
485
472
  schema={baseSchema}
486
473
  validator={validator}
@@ -504,7 +491,7 @@ useEffect(()=>{
504
491
  defaultActiveKey="_configured"
505
492
  id="domain-tabs"
506
493
  className="mb-3"
507
- onClick={()=>{setSchema({})}}
494
+
508
495
  >
509
496
  {getTabs()}
510
497
  </Tabs>
@@ -513,20 +500,27 @@ useEffect(()=>{
513
500
  <Grid item><h2>{schema?.title}</h2><p></p></Grid>
514
501
  <Grid item>{ReactHtmlParser(schema?.htmlDescription)}</Grid>
515
502
  </Grid>
516
-
503
+ <fieldset disabled={!enableSchema}>
517
504
  <Form
518
505
  schema={schema}
519
506
  validator={validator}
520
507
  uiSchema={uiSchema}
521
- onChange={(e) => {
508
+ onChange={(e,id) => {
522
509
  const s = sensorMap.get(e.formData.mac_address)
523
- s._changesMade=true
524
- setSensorData(e.formData)
510
+ if(s) {
511
+ s._changesMade=true
512
+ s.config = e.formData
513
+ setSensorData(e.formData)
514
+ }
515
+
516
+ if (id=="root_params_sensorClass") {
517
+ setSensorClassChanged(true)
518
+ }
519
+
525
520
  }
526
521
  }
527
522
  onSubmit={({ formData }, e) => {
528
523
  updateSensorData(formData)
529
- setSchema({})
530
524
  alert("Changes saved")
531
525
  }}
532
526
  onError={log('errors')}
@@ -537,11 +531,12 @@ useEffect(()=>{
537
531
  <Button variant="contained" color="secondary" onClick={(e)=>confirmDelete(sensorData.mac_address)}>Delete</Button>
538
532
  </div>
539
533
  </Form>
540
-
534
+ </fieldset>
541
535
 
542
536
  </div>
543
537
  </div>
544
538
  )
545
539
 
546
540
 
547
- }
541
+ }
542
+ export default BTConfig