@@ -14,16 +14,16 @@ const locationOptions = {
14
14
} ;
15
15
16
16
var zoomLevel = 17 ;
17
-
18
17
var mqtt_client , map , breadCrumbLine , locationCircle , locationChart , temperatureChart ;
19
-
20
18
var mqtt_message_count = 0 ;
21
-
22
-
23
19
let statusText = document . getElementById ( "status" ) ;
24
20
let locationText = document . getElementById ( "location" )
25
-
26
21
let npositions = 0 ;
22
+ var connectOptions = { } ;
23
+ let positionUserName = "keith" ; // If you get a position from mqtt topic position/$user then update the UI with that position
24
+ let userLastPositions = { } ; // dictionary of most recent posObj keyed by user name
25
+ // make this null if you want to use your local position measurementes
26
+ // TODO: Make this configurable in the UI
27
27
28
28
29
29
function dashboard_init ( ) {
@@ -38,7 +38,6 @@ function dashboard_init() {
38
38
}
39
39
40
40
41
-
42
41
function mqtt_init ( ) {
43
42
// Create a client instance
44
43
mqtt_client = new Paho . MQTT . Client ( loc . hostname , Number ( loc . port ) , "clientId" ) ;
@@ -60,7 +59,7 @@ function mqtt_login() {
60
59
let username = document . getElementById ( "username" ) . value ;
61
60
let password = document . getElementById ( "password" ) . value ;
62
61
// For more options, see here: https://www.eclipse.org/paho/files/jsdoc/Paho.MQTT.Client.html
63
- let options = {
62
+ connectOptions = {
64
63
timeout :3 ,
65
64
userName :username ,
66
65
password :password ,
@@ -72,7 +71,7 @@ function mqtt_login() {
72
71
73
72
// setStatus("Connecting...");
74
73
$ ( '#debug_logs' ) . append ( "MQTT Client connecting..." ) ;
75
- mqtt_client . connect ( options ) ;
74
+ mqtt_client . connect ( connectOptions ) ;
76
75
return false
77
76
78
77
}
@@ -82,10 +81,8 @@ function onConnect() {
82
81
// Once a connection has been made, make a subscription and send a message.
83
82
console . log ( "onConnect" ) ;
84
83
mqtt_client . subscribe ( "ekayak" ) ;
85
- // let message = new Paho.MQTT.Message("Hello");
86
- // message.destinationName = "World";
87
- // mqtt_client.send(message);
88
- // setStatus("Connected");
84
+ mqtt_client . subscribe ( "position/+" ) ; // subscribe to all users sending positions
85
+
89
86
$ ( '#debug_logs' ) . append ( "MQTT Client Connected!" ) ;
90
87
$ ( '.login_icon' ) . removeClass ( 'text-red-500' ) ;
91
88
$ ( '.login_icon' ) . addClass ( 'text-green-500' ) ;
@@ -103,11 +100,32 @@ function onConnectionLost(responseObject) {
103
100
}
104
101
105
102
103
+ function updateTelemetry ( data ) {
104
+ addData ( temperatureChart , mqtt_message_count , [ data . internal_temp , data . external_temp , data . esc_temp , data . relative_humidity ] )
105
+
106
+ let voltStr = data . battery_voltage . toFixed ( 1 ) + ' V' ;
107
+ let tempStr = data . esc_temp . toFixed ( 1 ) + ' Deg.' ;
108
+ let rpmStr = data . rpm . toFixed ( 0 ) ;
109
+ $ ( '#battery_voltage' ) . html ( voltStr ) ;
110
+ $ ( '#controller_temp' ) . html ( tempStr ) ;
111
+ $ ( '#rpm' ) . html ( rpmStr ) ;
112
+ }
113
+
114
+ function updateUserPosition ( sendingUser , posobj ) {
115
+ // called a position received from a sendingUser
116
+ // may or may not be a new user
117
+
118
+ userLastPositions [ sendingUser ] = posobj ;
119
+ console . log ( "Got position from " , sendingUser , posobj , Object . keys ( userLastPositions ) ) ;
120
+
121
+ // TODO: Update UI so our user can choose which person to display positionUserNames - could even use distances
122
+
123
+ }
106
124
107
125
function onMessageArrived ( message ) {
108
126
console . log ( "onMessageArrived:" , message . payloadString ) ;
109
127
console . log ( message )
110
- console . log ( "Destionation " , message . destinationName ) ;
128
+ console . log ( "Destination " , message . destinationName ) ;
111
129
console . log ( "QoS" , message . qos ) ;
112
130
console . log ( "retained" , message . retained ) ;
113
131
console . log ( "Duplicate" , message . duplicate ) ;
@@ -117,23 +135,26 @@ function onMessageArrived(message) {
117
135
$ ( '#debug_logs' ) . append ( message . payloadString ) ;
118
136
119
137
let data = JSON . parse ( message . payloadString ) ;
120
-
121
- addData ( temperatureChart , mqtt_message_count , [ data . internal_temp , data . external_temp , data . esc_temp , data . relative_humidity ] )
138
+ const destName = message . destinationName ;
122
139
123
- let voltStr = data . battery_voltage . toFixed ( 1 ) + ' V' ;
124
- let tempStr = data . esc_temp . toFixed ( 1 ) + ' Deg.' ;
125
- let rpmStr = data . rpm . toFixed ( 0 ) ;
126
- $ ( '#battery_voltage' ) . html ( voltStr ) ;
127
- $ ( '#controller_temp' ) . html ( tempStr ) ;
128
- $ ( '#rpm' ) . html ( rpmStr ) ;
140
+ if ( destName == "ekayak" ) {
141
+ updateTelemetry ( data ) ;
142
+ } else if ( destName . startsWith ( "position/" ) ) {
143
+ const sendingUser = destName . split ( "/" ) [ 1 ] ;
144
+ updateUserPosition ( sendingUser , data ) ;
145
+
146
+ if ( sendingUser == positionUserName ) {
147
+ updatePosition ( data ) ;
148
+ }
149
+ }
150
+
151
+
129
152
130
153
mqtt_message_count += 1 ;
131
154
132
155
}
133
156
134
157
135
-
136
-
137
158
function map_init ( ) {
138
159
map = L . map ( 'map' ) . fitWorld ( ) ;
139
160
L . tileLayer ( 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' , {
@@ -301,18 +322,31 @@ function location_chart_init() {
301
322
302
323
}
303
324
325
+ function positionToObject ( position ) {
326
+ // JSON can't serialise the position data for some reason - so make our own
304
327
328
+ const c = position . coords ;
305
329
330
+ let positionObj = { latitude :c . latitude ,
331
+ longitude :c . longitude ,
332
+ accuracy :c . accuracy ,
333
+ speed :c . speed ,
334
+ heading :c . heading ,
335
+ altitude :c . altitude ,
336
+ altitudeAccuracy :c . altitudeAccuracy ,
337
+ timestamp :position . timestamp } ;
306
338
307
- function locationSuccess ( position ) {
308
- const c = position . coords ;
309
- // locationText.textContent = `lat/long:${c.latitude}/${c.longitude} speed:${c.speed} heading:${c.heading} altitude:${c.altitude} accuracy:${c.accuracy} altaccuracy:${c.altitudeAccuracy} timestamp:${position.timestamp}`;
339
+ return positionObj ;
340
+ }
341
+
342
+ function updatePosition ( positionObj ) {
343
+ const c = positionObj ;
310
344
const latlng = [ c . latitude , c . longitude ] ;
311
345
if ( npositions == 0 ) {
312
346
//map.flyTo(latlng, Number(zoomLevel), {animate:true}); // Flying takes too long and stops when the next location comes in
313
- map . setView ( latlng , zoomLevel ) ;
347
+ map . setView ( latlng , zoomLevel ) ; // Set zoom level the first time as we started in world view
314
348
} else {
315
- map . panTo ( latlng ) ;
349
+ map . panTo ( latlng ) ; // user might use UI to change zoom level - don't want to set back to default
316
350
}
317
351
breadCrumbLine . addLatLng ( latlng ) ;
318
352
locationCircle . setLatLng ( latlng ) ;
@@ -322,11 +356,32 @@ function locationSuccess(position) {
322
356
323
357
$ ( '#gps_speed' ) . html ( `${ Math . round ( c . speed * 36 ) / 10 } km/h` ) ;
324
358
$ ( '#current_trip' ) . html ( '0 km' ) ;
325
- $ ( '#debug_logs' ) . append ( `lat/long:${ c . latitude } /${ c . longitude } speed:${ c . speed } heading:${ c . heading } altitude:${ c . altitude } accuracy:${ c . accuracy } altaccuracy:${ c . altitudeAccuracy } timestamp:${ position . timestamp } ` ) ;
359
+ $ ( '#debug_logs' ) . append ( `lat/long:${ c . latitude } /${ c . longitude } speed:${ c . speed } heading:${ c . heading } altitude:${ c . altitude } accuracy:${ c . accuracy } altaccuracy:${ c . altitudeAccuracy } timestamp:${ c . timestamp } ` ) ;
326
360
$ ( '#debug_logs' ) . append ( `<br>${ Math . round ( c . speed * 36 ) / 10 } km/h` ) ;
327
361
328
362
addData ( locationChart , npositions , [ c . speed , c . heading ] )
363
+ }
364
+
365
+
366
+ function locationSuccess ( position ) {
329
367
368
+ const posobj = positionToObject ( position ) ;
369
+
370
+ if ( positionUserName === null ) { // update UI if we're not using positions from MQTT
371
+ updatePosition ( posobj ) ; // update UI
372
+
373
+ }
374
+
375
+ // send data to mqtt
376
+ const payload = JSON . stringify ( posobj ) ;
377
+ const topic = 'position/' + connectOptions . userName ;
378
+ const qos = 0 ; // best effort
379
+ const retained = true ; // Let new subscribers know our last position as soon as they subscribe
380
+ try {
381
+ mqtt_client . send ( topic , payload , qos , retained ) ;
382
+ } catch ( invalidState ) {
383
+ // Client isn't connected. Oh well. Don't really care I don't think.
384
+ }
330
385
}
331
386
332
387
function locationError ( error ) {
@@ -361,9 +416,6 @@ function removeData(chart) {
361
416
chart . update ( ) ;
362
417
}
363
418
364
-
365
-
366
-
367
419
// On Apline ready
368
420
document . addEventListener ( 'alpine:init' , ( ) => {
369
421
dashboard_init ( ) ;
0 commit comments