bt-sensors-plugin-sk 1.1.0 → 1.2.0-beta.0.0.1.test

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.
@@ -0,0 +1,368 @@
1
+ import Form from '@rjsf/core' ;
2
+ import validator from '@rjsf/validator-ajv8';
3
+ import React from 'react'
4
+ import {useEffect, useState} from 'react'
5
+
6
+ import {Button, Grid} from '@material-ui/core';
7
+
8
+
9
+ import { SignalCellular0Bar, SignalCellular1Bar, SignalCellular2Bar, SignalCellular3Bar, SignalCellular4Bar, SignalCellularConnectedNoInternet0Bar } from '@material-ui/icons';
10
+
11
+ const log = (type) => console.log.bind(console, type);
12
+
13
+ import ListGroup from 'react-bootstrap/ListGroup';
14
+ import { ListGroupItem } from 'react-bootstrap';
15
+
16
+ import ProgressBar from 'react-bootstrap/ProgressBar';
17
+
18
+
19
+ var _sensorMap
20
+
21
+ export default (props) => {
22
+
23
+ const hideSubmit= {
24
+ 'ui:submitButtonOptions': {
25
+ props: {
26
+ disabled: false,
27
+ className: 'btn btn-info',
28
+ },
29
+ norender: true,
30
+ submitText: 'Submit',
31
+ },
32
+ }
33
+ const [baseSchema, setBaseSchema] = useState({})
34
+ const [baseData, setBaseData] = useState({})
35
+
36
+ const [schema, setSchema] = useState({})
37
+ const [ uiSchema, setUISchema] = useState(hideSubmit )
38
+ const [sensorList, setSensorList] = useState([])
39
+
40
+ const [sensorData, setSensorData] = useState()
41
+ const [sensorMap, setSensorMap ] = useState(new Map() )
42
+
43
+ const [progress, setProgress ] = useState({
44
+ "progress":0, "maxTimeout": 100,
45
+ "deviceCount":0,
46
+ "totalDevices":0})
47
+
48
+
49
+ const [pluginState, setPluginState ] = useState("unknown")
50
+ const [error, setError ] = useState()
51
+
52
+
53
+ function sendJSONData(cmd, data){
54
+
55
+ console.log(`sending ${cmd}`)
56
+ console.log(data)
57
+ const headers = new Headers();
58
+ headers.append("Content-Type", "application/json");
59
+ return fetch(`/plugins/bt-sensors-plugin-sk/${cmd}`, {
60
+ credentials: 'include',
61
+ method: 'POST',
62
+ body: JSON.stringify(data),
63
+ headers:headers
64
+ })
65
+ }
66
+
67
+ async function fetchJSONData(path){
68
+ console.log(`fetching ${path}`)
69
+
70
+ return fetch(`/plugins/bt-sensors-plugin-sk/${path}`, {
71
+ credentials: 'include'
72
+ })
73
+
74
+ }
75
+
76
+ async function getSensorData(){
77
+
78
+ const response = await fetchJSONData("sensors")
79
+ if (response.status!=200){
80
+ throw new Error(`Unable get sensor data: ${response.statusText} (${response.status}) `)
81
+ }
82
+ const json = await response.json()
83
+ console.log(json)
84
+ return json
85
+
86
+ }
87
+
88
+ async function getBaseData(){
89
+
90
+ const response = await fetchJSONData("base")
91
+ if (response.status!=200){
92
+ throw new Error(`Unable get base data: ${response.statusText} (${response.status}) `)
93
+ }
94
+ const json = await response.json()
95
+ console.log(json)
96
+ return json
97
+ }
98
+ async function getProgress(){
99
+
100
+ const response = await fetchJSONData("progress")
101
+ if (response.status!=200){
102
+ throw new Error(`Unable get progres: ${response.statusText} (${response.status}) `)
103
+ }
104
+ const json = await response.json()
105
+ console.log(json)
106
+ return json
107
+ }
108
+
109
+ function updateSensorData(data){
110
+ sendJSONData("sendSensorData", data).then((response)=>{
111
+ if (response.status != 200) {
112
+ throw new Error(response.statusText)
113
+ }
114
+ debugger
115
+ sensorMap.get(data.mac_address).config = data
116
+
117
+ })
118
+ }
119
+
120
+ function undoChanges(mac) {
121
+ setSensorData( sensorMap.get(mac).config )
122
+ }
123
+
124
+ function removeSensorData(mac){
125
+ try{
126
+
127
+ sendJSONData("removeSensorData", {mac_address:mac} ).then((response)=>{
128
+ if (response.status != 200) {
129
+ throw new Error(response.statusText)
130
+ }
131
+ })
132
+
133
+ _sensorMap.delete(mac)
134
+
135
+ setSensorMap(new Map(_sensorMap))
136
+ setSchema( {} )
137
+ } catch {(e)=>
138
+ setError( new Error(`Couldn't remove ${mac}: ${e}`))
139
+ }
140
+
141
+ }
142
+
143
+
144
+ function updateBaseData(data){
145
+ sendJSONData("sendBaseData", data).then( (response )=>{
146
+ if (response.status != 200) {
147
+ setError(new Error(`Unable to update base data: ${response.statusText} (${response.status})`))
148
+ } else {
149
+ getProgress().then((json)=>{
150
+ setProgress(json)
151
+ }).catch((e)=>{
152
+ setError(e)
153
+ })
154
+ refreshSensors()
155
+ }
156
+ })
157
+ }
158
+
159
+
160
+ function refreshSensors(){
161
+ console.log('refreshing sensor map')
162
+
163
+ getSensorData().then((sensors)=>{
164
+ setSensorMap (new Map(sensors.map((sensor)=>[sensor.info.mac,sensor])));
165
+ })
166
+ .catch((e)=>{
167
+ setError(e)
168
+ })
169
+ }
170
+
171
+
172
+ useEffect(()=>{
173
+
174
+ fetchJSONData("sendPluginState").then( async (response)=> {
175
+ const json = await response.json()
176
+ setPluginState(json.state)
177
+ console.log("Setting up eventsource")
178
+ const eventSource = new EventSource("/plugins/bt-sensors-plugin-sk/sse")
179
+
180
+ eventSource.addEventListener("newsensor", (event) => {
181
+ let json = JSON.parse(event.data)
182
+
183
+ if (!_sensorMap.has(json.info.mac)) {
184
+ console.log(`New sensor: ${json.info.mac}`)
185
+ setSensorMap(new Map(_sensorMap.set(json.info.mac, json)))
186
+ }
187
+ });
188
+
189
+ eventSource.addEventListener("sensorchanged", (event) => {
190
+ let json = JSON.parse(event.data)
191
+
192
+ if (_sensorMap.has(json.mac)) {
193
+ let sensor = _sensorMap.get(json.mac)
194
+ Object.assign(sensor.info, json )
195
+ setSensorMap(new Map ( _sensorMap ))
196
+ }
197
+ });
198
+ eventSource.addEventListener("progress", (event) => {
199
+ const json = JSON.parse(event.data)
200
+ setProgress(json)
201
+ console.log(json)
202
+ });
203
+
204
+ eventSource.addEventListener("pluginstate", (event) => {
205
+ const json = JSON.parse(event.data)
206
+ setPluginState(json.state)
207
+ });
208
+ return () => eventSource.close();
209
+ })
210
+
211
+ .catch( (e) => {
212
+ setError(e)
213
+ }
214
+ )
215
+ },[])
216
+
217
+ useEffect(()=>{
218
+ if (pluginState=="started"){
219
+ refreshSensors()
220
+
221
+ getBaseData().then((json) => {
222
+ setBaseSchema(json.schema);
223
+ setBaseData(json.data);
224
+ }).catch((e)=>{
225
+ setError(e)
226
+ })
227
+
228
+ getProgress().then((json)=>{
229
+ setProgress(json)
230
+ }).catch((e)=>{
231
+ setError(e)
232
+ })
233
+
234
+ } else{
235
+ setSensorMap(new Map())
236
+ setBaseSchema({})
237
+ setBaseData({})
238
+ }
239
+
240
+ },[pluginState])
241
+
242
+ useEffect(()=>{
243
+ console.log(error)
244
+ },[error])
245
+
246
+ function confirmDelete(mac){
247
+ const result = window.confirm(`Delete configuration for ${mac}?`)
248
+ if (result)
249
+ removeSensorData(mac)
250
+ }
251
+
252
+ function signalStrengthIcon(sensor){
253
+ if (sensor.info.lastContactDelta ==null || sensor.info.lastContactDelta > sensor.config.discoveryTimeout)
254
+ return <SignalCellularConnectedNoInternet0Bar/>
255
+
256
+ if (sensor.info.signalStrength > 80)
257
+ return <SignalCellular4Bar/>
258
+
259
+ if (sensor.info.signalStrength > 60)
260
+ return <SignalCellular3Bar/>
261
+
262
+ if (sensor.info.signalStrength > 40)
263
+ return <SignalCellular2Bar/>
264
+
265
+ if (sensor.info.signalStrength > 20)
266
+ return <SignalCellular1Bar/>
267
+
268
+ return <SignalCellular0Bar/>
269
+
270
+ }
271
+ useEffect(()=>{
272
+ _sensorMap = sensorMap
273
+
274
+ setSensorList(
275
+
276
+ Array.from(sensorMap.entries()).map((entry) => {
277
+ const sensor = sensorMap.get(entry[0]);
278
+ const config= sensor.config
279
+ const hasConfig = Object.keys(config).length>0;
280
+
281
+
282
+ return <ListGroupItem action
283
+ onClick={()=>{
284
+ if (sensor){
285
+ config.mac_address=entry[0]
286
+ setSchema(sensor.schema)
287
+ setSensorData(config)
288
+ }
289
+ }
290
+ }>
291
+ <div class="d-flex justify-content-between align-items-center" style={hasConfig?{fontWeight:"normal"}:{fontStyle:"italic"}}>
292
+ {`${sensor.info.name} MAC: ${sensor.info.mac} RSSI: ${ifNullNaN(sensor.info.RSSI)}` }
293
+ <div class="d-flex justify-content-between ">
294
+ {
295
+ signalStrengthIcon(sensor)
296
+ }
297
+ </div>
298
+ </div>
299
+ </ListGroupItem>
300
+ })
301
+ )
302
+
303
+ },[sensorMap]
304
+ )
305
+
306
+ function ifNullNaN(value){
307
+ return value==null? NaN : value
308
+ }
309
+
310
+
311
+ if (pluginState=="stopped")
312
+ return (<h1 >Enable plugin to see configuration</h1>)
313
+ else
314
+ return(
315
+ <div>
316
+ {error?<h2 style="color: red;">{error.message}</h2>:""}
317
+ <Form
318
+ schema={baseSchema}
319
+ validator={validator}
320
+ onChange={(e) => setBaseData(e.formData)}
321
+ onSubmit={ ({ formData }, e) => {setSensorData(null); updateBaseData(formData) }}
322
+ onError={log('errors')}
323
+ formData={baseData}
324
+ />
325
+ <p></p>
326
+ <p></p>
327
+ { (progress.deviceCount<progress.totalDevices)?
328
+ <ProgressBar max={progress.maxTimeout}
329
+ now={progress.progress}
330
+ />:""
331
+ }
332
+ <h2>{`${sensorMap.size>0?" Bluetooth Devices click to configure":""}`}</h2>
333
+ <p></p>
334
+ <div style={{paddingBottom: 20}} class="d-flex flex-wrap justify-content-start align-items-start">
335
+ <ListGroup style={{ maxHeight: '300px', overflowY: 'auto' }}>
336
+ {sensorList}
337
+ </ListGroup>
338
+ <div style= {{ paddingLeft: 10, paddingTop: 10, display: (Object.keys(schema).length==0)? "none" :"" }} >
339
+ <Form
340
+ schema={schema}
341
+ validator={validator}
342
+ uiSchema={uiSchema}
343
+ onChange={(e) => setSensorData(e.formData)}
344
+ onSubmit={({ formData }, e) => {
345
+ console.log(formData)
346
+ updateSensorData(formData)
347
+ setSchema({})
348
+ alert("Changes saved")
349
+ }}
350
+ onError={log('errors')}
351
+ formData={sensorData}>
352
+ <div>
353
+ <Grid direction="row" style={{spacing:5}}>
354
+ <Button type='submit' color="primary" variant="contained">Save</Button>
355
+ <Button variant="contained" onClick={()=>{undoChanges(sensorData.mac_address)}}>Undo</Button>
356
+ <Button variant="contained" color="secondary" onClick={(e)=>confirmDelete(sensorData.mac_address)}>Delete</Button>
357
+
358
+ </Grid>
359
+ </div>
360
+ </Form>
361
+
362
+ </div>
363
+ </div>
364
+ </div>
365
+ )
366
+
367
+
368
+ }
package/src/index.js ADDED
File without changes
@@ -0,0 +1,71 @@
1
+ // const HtmlWebpackPlugin = require('html-webpack-plugin');
2
+ const path = require('path');
3
+
4
+ const { ModuleFederationPlugin } = require('webpack').container;
5
+ const { WatchIgnorePlugin } = require('webpack')
6
+
7
+ require('@signalk/server-admin-ui-dependencies')
8
+
9
+ const packageJson = require('./package')
10
+
11
+ console.log(packageJson.name.replace(/[-@/]/g, '_'))
12
+
13
+ module.exports = {
14
+ entry: './src/index',
15
+ mode: 'development',
16
+ output: {
17
+ path: path.resolve(__dirname, 'public')
18
+ },
19
+ module: {
20
+ rules: [
21
+ {
22
+ test: /\.js?$/,
23
+ loader: 'babel-loader',
24
+ exclude: /node_modules/,
25
+ options: {
26
+ presets: ['@babel/preset-react'],
27
+ },
28
+ },
29
+ {
30
+ test: /\.jsx?$/,
31
+ loader: 'babel-loader',
32
+ exclude: /node_modules/,
33
+ options: {
34
+ presets: ['@babel/preset-react'],
35
+ },
36
+ },
37
+ {
38
+ test: /\.css$/,
39
+ use: [
40
+ 'style-loader',
41
+ 'css-loader'
42
+ ]
43
+ },
44
+ {
45
+ test: /\.(png|svg|jpg|gif)$/,
46
+ loader:
47
+ 'file-loader',
48
+ options: {
49
+ name: '[path][name].[ext]',
50
+ },
51
+ }
52
+ ],
53
+ },
54
+ plugins: [
55
+ new ModuleFederationPlugin({
56
+ name: 'Bluetooth Sensors for Signalk',
57
+ library: { type: 'var', name: packageJson.name.replace(/[-@/]/g, '_') },
58
+ filename: 'remoteEntry.js',
59
+ exposes: {
60
+ './PluginConfigurationPanel': './src/components/PluginConfigurationPanel',
61
+ },
62
+ shared: [{ react: { singleton: false, strictVersion:true } }],
63
+ }),
64
+ new WatchIgnorePlugin({
65
+ paths: [path.resolve(__dirname, 'public/')]
66
+ })
67
+ // new HtmlWebpackPlugin({
68
+ // template: './public/index.html',
69
+ // }),
70
+ ],
71
+ };