@mxtommy/kip 1.2.1 → 1.3.0

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 (315) hide show
  1. package/.angulardoc.json +3 -3
  2. package/CHANGELOG.md +145 -124
  3. package/CONTRIBUTORS.md +16 -13
  4. package/README.md +102 -101
  5. package/angular.json +162 -152
  6. package/karma.conf.js +31 -31
  7. package/package.json +87 -80
  8. package/public/3rdpartylicenses.txt +317 -62
  9. package/public/assets/NoSleep.min.js +1 -1
  10. package/public/assets/fontawesome6/css/all.min.css +6 -0
  11. package/public/assets/fontawesome6/webfonts/fa-brands-400.ttf +0 -0
  12. package/public/assets/fontawesome6/webfonts/fa-brands-400.woff2 +0 -0
  13. package/public/assets/fontawesome6/webfonts/fa-regular-400.ttf +0 -0
  14. package/public/assets/fontawesome6/webfonts/fa-regular-400.woff2 +0 -0
  15. package/public/assets/fontawesome6/webfonts/fa-solid-900.ttf +0 -0
  16. package/public/assets/fontawesome6/webfonts/fa-solid-900.woff2 +0 -0
  17. package/public/assets/fontawesome6/webfonts/fa-v4compatibility.ttf +0 -0
  18. package/public/assets/fontawesome6/webfonts/fa-v4compatibility.woff2 +0 -0
  19. package/public/assets/icon-192x192.png +0 -0
  20. package/public/assets/icon-256x256.png +0 -0
  21. package/public/assets/icon-384x384.png +0 -0
  22. package/public/assets/icon-512x512.png +0 -0
  23. package/public/assets/steelseries-min.js +25 -25
  24. package/public/assets/steelseries-min.js.map +8 -8
  25. package/public/assets/steelseries.js +15834 -15834
  26. package/public/assets/svg-autopilot-inkscape-plain.svg +983 -983
  27. package/public/assets/svg-wind-inkscape.svg +1358 -1358
  28. package/public/assets/tween.js +381 -381
  29. package/public/index.html +19 -20
  30. package/public/main-es2018.98175eb4c61ccaf7eb17.js +1 -0
  31. package/public/main-es5.98175eb4c61ccaf7eb17.js +1 -0
  32. package/public/manifest.json +33 -0
  33. package/public/polyfills-es2018.3a61665863c173cd6ba3.js +1 -0
  34. package/public/polyfills-es5.44827ae4ff4e41de51fb.js +1 -0
  35. package/public/runtime-es2018.baedb88c6d2abacae2b8.js +1 -0
  36. package/public/runtime-es5.baedb88c6d2abacae2b8.js +1 -0
  37. package/public/styles.b92ae2c466c89712209d.css +5 -0
  38. package/src/app/alarm-menu/alarm-menu.component.html +55 -55
  39. package/src/app/alarm-menu/alarm-menu.component.scss +52 -53
  40. package/src/app/alarm-menu/alarm-menu.component.spec.ts +25 -25
  41. package/src/app/alarm-menu/alarm-menu.component.ts +186 -186
  42. package/src/app/app-help/app-help.component.css +4 -4
  43. package/src/app/app-help/app-help.component.html +135 -121
  44. package/src/app/app-help/app-help.component.ts +45 -45
  45. package/src/app/app.component.css +39 -39
  46. package/src/app/app.component.html +93 -93
  47. package/src/app/app.component.scss +79 -79
  48. package/src/app/app.component.spec.ts +32 -32
  49. package/src/app/app.component.ts +191 -192
  50. package/src/app/app.module.ts +200 -200
  51. package/src/app/config.blank.const.ts +51 -51
  52. package/src/app/config.blank.notification.const.ts +19 -19
  53. package/src/app/config.blank.units.const.ts +23 -23
  54. package/src/app/config.demo.const.ts +383 -382
  55. package/src/app/data-browser/data-browser.component.css +29 -29
  56. package/src/app/data-browser/data-browser.component.html +44 -44
  57. package/src/app/data-browser/data-browser.component.spec.ts +25 -25
  58. package/src/app/data-browser/data-browser.component.ts +91 -91
  59. package/src/app/data-browser-row/data-browser-row-unit-modal.html +17 -17
  60. package/src/app/data-browser-row/data-browser-row.component.css +9 -9
  61. package/src/app/data-browser-row/data-browser-row.component.html +4 -4
  62. package/src/app/data-browser-row/data-browser-row.component.ts +78 -78
  63. package/src/app/data-set.service.ts +273 -273
  64. package/src/app/dynamic-widget.directive.ts +11 -11
  65. package/src/app/gauge-steel/gauge-steel.component.css +4 -4
  66. package/src/app/gauge-steel/gauge-steel.component.html +4 -4
  67. package/src/app/gauge-steel/gauge-steel.component.spec.ts +25 -25
  68. package/src/app/gauge-steel/gauge-steel.component.ts +282 -282
  69. package/src/app/gauges-module/base-gauge.ts +301 -0
  70. package/src/app/gauges-module/gauges.module.ts +17 -0
  71. package/src/app/gauges-module/linear-gauge.ts +50 -0
  72. package/src/app/gauges-module/radial-gauge.ts +48 -0
  73. package/src/app/layout-split/layout-split.component.html +30 -30
  74. package/src/app/layout-split/layout-split.component.scss +33 -33
  75. package/src/app/layout-split/layout-split.component.spec.ts +25 -25
  76. package/src/app/layout-split/layout-split.component.ts +59 -59
  77. package/src/app/layout-splits.service.ts +284 -284
  78. package/src/app/modal-path-selector/modal-path-selector.component.html +62 -62
  79. package/src/app/modal-path-selector/modal-path-selector.component.scss +39 -39
  80. package/src/app/modal-path-selector/modal-path-selector.component.spec.ts +25 -25
  81. package/src/app/modal-path-selector/modal-path-selector.component.ts +132 -132
  82. package/src/app/modal-widget/modal-widget.component.css +32 -32
  83. package/src/app/modal-widget/modal-widget.component.html +341 -334
  84. package/src/app/modal-widget/modal-widget.component.spec.ts +25 -25
  85. package/src/app/modal-widget/modal-widget.component.ts +84 -84
  86. package/src/app/notifications.service.ts +392 -387
  87. package/src/app/object-keys.pipe.spec.ts +8 -8
  88. package/src/app/object-keys.pipe.ts +13 -13
  89. package/src/app/reset-config/reset-config.component.html +3 -3
  90. package/src/app/reset-config/reset-config.component.spec.ts +25 -25
  91. package/src/app/reset-config/reset-config.component.ts +31 -31
  92. package/src/app/root-display/root-display.component.html +4 -4
  93. package/src/app/root-display/root-display.component.spec.ts +25 -25
  94. package/src/app/root-display/root-display.component.ts +57 -57
  95. package/src/app/safe.pipe.ts +15 -15
  96. package/src/app/settings/settings.component.css +9 -9
  97. package/src/app/settings/settings.component.html +25 -25
  98. package/src/app/settings/settings.component.spec.ts +25 -25
  99. package/src/app/settings/settings.component.ts +22 -22
  100. package/src/app/settings-config/settings-config.component.css +38 -38
  101. package/src/app/settings-config/settings-config.component.spec.ts +25 -25
  102. package/src/app/settings-config/settings-config.component.ts +161 -161
  103. package/src/app/settings-datasets/settings-datasets.component.html +43 -43
  104. package/src/app/settings-datasets/settings-datasets.component.scss +39 -39
  105. package/src/app/settings-datasets/settings-datasets.component.spec.ts +25 -25
  106. package/src/app/settings-datasets/settings-datasets.component.ts +98 -98
  107. package/src/app/settings-datasets/settings-datasets.modal.html +54 -54
  108. package/src/app/settings-notifications/settings-notifications.component.html +65 -65
  109. package/src/app/settings-notifications/settings-notifications.component.spec.ts +25 -25
  110. package/src/app/settings-notifications/settings-notifications.component.ts +29 -29
  111. package/src/app/settings-signalk/settings-signalk.component.html +8 -8
  112. package/src/app/settings-signalk/settings-signalk.component.spec.ts +25 -25
  113. package/src/app/settings-signalk/settings-signalk.component.ts +6 -17
  114. package/src/app/settings-units/settings-units.component.css +4 -4
  115. package/src/app/settings-units/settings-units.component.html +19 -19
  116. package/src/app/settings-units/settings-units.component.spec.ts +25 -25
  117. package/src/app/settings-units/settings-units.component.ts +62 -62
  118. package/src/app/settings-zones/settings-zones.component.css +21 -21
  119. package/src/app/settings-zones/settings-zones.component.html +70 -70
  120. package/src/app/settings-zones/settings-zones.modal.html +38 -38
  121. package/src/app/signalk-connection.service.ts +344 -344
  122. package/src/app/signalk-delta.service.spec.ts +15 -15
  123. package/src/app/signalk-delta.service.ts +97 -97
  124. package/src/app/signalk-full.service.ts +99 -99
  125. package/src/app/signalk-interfaces.ts +129 -129
  126. package/src/app/signalk-requests.service.spec.ts +12 -12
  127. package/src/app/signalk-requests.service.ts +180 -180
  128. package/src/app/svg-autopilot/svg-autopilot.component.html +1036 -1036
  129. package/src/app/svg-autopilot/svg-autopilot.component.spec.ts +25 -25
  130. package/src/app/svg-autopilot/svg-autopilot.component.ts +174 -174
  131. package/src/app/svg-simple-linear-gauge/svg-simple-linear-gauge.component.html +119 -119
  132. package/src/app/svg-simple-linear-gauge/svg-simple-linear-gauge.component.spec.ts +25 -25
  133. package/src/app/svg-simple-linear-gauge/svg-simple-linear-gauge.component.ts +49 -49
  134. package/src/app/svg-wind/svg-wind.component.html +969 -969
  135. package/src/app/svg-wind/svg-wind.component.scss +76 -76
  136. package/src/app/svg-wind/svg-wind.component.spec.ts +25 -25
  137. package/src/app/svg-wind/svg-wind.component.ts +280 -280
  138. package/src/app/unit-window/unit-window.component.css +37 -37
  139. package/src/app/unit-window/unit-window.component.html +8 -8
  140. package/src/app/unit-window/unit-window.component.spec.ts +25 -25
  141. package/src/app/unit-window/unit-window.component.ts +134 -134
  142. package/src/app/unit-window/unit-window.modal.html +24 -24
  143. package/src/app/units.service.ts +300 -300
  144. package/src/app/widget-autopilot/widget-autopilot.component.html +78 -85
  145. package/src/app/widget-autopilot/widget-autopilot.component.scss +191 -191
  146. package/src/app/widget-autopilot/widget-autopilot.component.spec.ts +25 -25
  147. package/src/app/widget-autopilot/widget-autopilot.component.ts +774 -781
  148. package/src/app/widget-blank/widget-blank.component.scss +21 -22
  149. package/src/app/widget-blank/widget-blank.component.spec.ts +25 -25
  150. package/src/app/widget-blank/widget-blank.component.ts +17 -17
  151. package/src/app/widget-gauge/widget-gauge.component.css +25 -25
  152. package/src/app/widget-gauge/widget-gauge.component.html +29 -29
  153. package/src/app/widget-gauge/widget-gauge.component.spec.ts +25 -25
  154. package/src/app/widget-gauge/widget-gauge.component.ts +120 -120
  155. package/src/app/widget-gauge-ng-linear/widget-gauge-ng-linear.component.html +126 -126
  156. package/src/app/widget-gauge-ng-linear/widget-gauge-ng-linear.component.scss +94 -93
  157. package/src/app/widget-gauge-ng-linear/widget-gauge-ng-linear.component.spec.ts +25 -25
  158. package/src/app/widget-gauge-ng-linear/widget-gauge-ng-linear.component.ts +424 -424
  159. package/src/app/widget-gauge-ng-radial/widget-gauge-ng-radial.component.html +122 -122
  160. package/src/app/widget-gauge-ng-radial/widget-gauge-ng-radial.component.scss +69 -69
  161. package/src/app/widget-gauge-ng-radial/widget-gauge-ng-radial.component.spec.ts +25 -25
  162. package/src/app/widget-gauge-ng-radial/widget-gauge-ng-radial.component.ts +553 -553
  163. package/src/app/widget-historical/widget-historical.component.html +14 -14
  164. package/src/app/widget-historical/widget-historical.component.spec.ts +25 -25
  165. package/src/app/widget-historical/widget-historical.component.ts +306 -307
  166. package/src/app/widget-iframe/widget-iframe.component.css +11 -11
  167. package/src/app/widget-iframe/widget-iframe.component.html +21 -21
  168. package/src/app/widget-iframe/widget-iframe.component.spec.ts +25 -25
  169. package/src/app/widget-iframe/widget-iframe.component.ts +63 -63
  170. package/src/app/widget-list.service.ts +135 -135
  171. package/src/app/widget-manager.service.ts +141 -140
  172. package/src/app/widget-numeric/widget-numeric.component.html +1 -1
  173. package/src/app/widget-numeric/widget-numeric.component.scss +3 -3
  174. package/src/app/widget-numeric/widget-numeric.component.spec.ts +25 -25
  175. package/src/app/widget-simple-linear/widget-simple-linear.component.html +28 -28
  176. package/src/app/widget-simple-linear/widget-simple-linear.component.scss +64 -64
  177. package/src/app/widget-simple-linear/widget-simple-linear.component.spec.ts +25 -25
  178. package/src/app/widget-simple-linear/widget-simple-linear.component.ts +199 -199
  179. package/src/app/widget-state/widget-state.component.html +27 -27
  180. package/src/app/widget-state/widget-state.component.scss +68 -68
  181. package/src/app/widget-state/widget-state.component.spec.ts +25 -25
  182. package/src/app/widget-state/widget-state.component.ts +178 -178
  183. package/src/app/widget-switch/widget-switch.component.css +69 -69
  184. package/src/app/widget-switch/widget-switch.component.html +17 -17
  185. package/src/app/widget-switch/widget-switch.component.spec.ts +25 -25
  186. package/src/app/widget-switch/widget-switch.component.ts +134 -134
  187. package/src/app/widget-text-generic/widget-text-generic.component.html +9 -9
  188. package/src/app/widget-text-generic/widget-text-generic.component.spec.ts +25 -25
  189. package/src/app/widget-tutorial/widget-tutorial.component.html +34 -34
  190. package/src/app/widget-tutorial/widget-tutorial.component.spec.ts +25 -25
  191. package/src/app/widget-tutorial/widget-tutorial.component.ts +18 -18
  192. package/src/app/widget-unknown/widget-unknown.component.spec.ts +25 -25
  193. package/src/app/widget-wind/widget-wind.component.css +23 -23
  194. package/src/app/widget-wind/widget-wind.component.html +20 -20
  195. package/src/app/widget-wind/widget-wind.component.spec.ts +25 -25
  196. package/src/app/widget-wind/widget-wind.component.ts +369 -369
  197. package/src/assets/NoSleep.min.js +1 -1
  198. package/src/assets/fontawesome6/css/all.min.css +6 -0
  199. package/src/assets/fontawesome6/webfonts/fa-brands-400.ttf +0 -0
  200. package/src/assets/fontawesome6/webfonts/fa-brands-400.woff2 +0 -0
  201. package/src/assets/fontawesome6/webfonts/fa-regular-400.ttf +0 -0
  202. package/src/assets/fontawesome6/webfonts/fa-regular-400.woff2 +0 -0
  203. package/src/assets/fontawesome6/webfonts/fa-solid-900.ttf +0 -0
  204. package/src/assets/fontawesome6/webfonts/fa-solid-900.woff2 +0 -0
  205. package/src/assets/fontawesome6/webfonts/fa-v4compatibility.ttf +0 -0
  206. package/src/assets/fontawesome6/webfonts/fa-v4compatibility.woff2 +0 -0
  207. package/src/assets/icon-192x192.png +0 -0
  208. package/src/assets/icon-256x256.png +0 -0
  209. package/src/assets/icon-384x384.png +0 -0
  210. package/src/assets/icon-512x512.png +0 -0
  211. package/src/assets/steelseries-min.js +25 -25
  212. package/src/assets/steelseries-min.js.map +8 -8
  213. package/src/assets/steelseries.js +15834 -15834
  214. package/src/assets/svg-autopilot-inkscape-plain.svg +983 -983
  215. package/src/assets/svg-wind-inkscape.svg +1358 -1358
  216. package/src/assets/tween.js +381 -381
  217. package/src/index.html +20 -20
  218. package/src/main.ts +11 -11
  219. package/src/manifest.json +33 -0
  220. package/src/polyfills.ts +80 -76
  221. package/src/styles.scss +11 -11
  222. package/src/themes/darkBlueTheme.scss +117 -116
  223. package/src/themes/defaultTheme.scss +50 -49
  224. package/src/themes/highContrastTheme.scss +47 -46
  225. package/src/themes/modernTheme.scss +143 -142
  226. package/src/themes/nightMode.scss +185 -184
  227. package/src/themes/platypusTheme.scss +80 -79
  228. package/src/themes/signalkTheme.scss +112 -111
  229. package/src/tsconfig.app.json +15 -15
  230. package/src/tsconfig.spec.json +20 -20
  231. package/tsconfig.json +23 -23
  232. package/tslint.json +143 -143
  233. package/public/assets/font-awesome/HELP-US-OUT.txt +0 -7
  234. package/public/assets/font-awesome/css/font-awesome.css +0 -2337
  235. package/public/assets/font-awesome/css/font-awesome.min.css +0 -4
  236. package/public/assets/font-awesome/desktop.ini +0 -4
  237. package/public/assets/font-awesome/fonts/FontAwesome.otf +0 -0
  238. package/public/assets/font-awesome/fonts/fontawesome-webfont.eot +0 -0
  239. package/public/assets/font-awesome/fonts/fontawesome-webfont.svg +0 -2671
  240. package/public/assets/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
  241. package/public/assets/font-awesome/fonts/fontawesome-webfont.woff +0 -0
  242. package/public/assets/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
  243. package/public/assets/font-awesome/less/animated.less +0 -34
  244. package/public/assets/font-awesome/less/bordered-pulled.less +0 -25
  245. package/public/assets/font-awesome/less/core.less +0 -12
  246. package/public/assets/font-awesome/less/fixed-width.less +0 -6
  247. package/public/assets/font-awesome/less/font-awesome.less +0 -18
  248. package/public/assets/font-awesome/less/icons.less +0 -789
  249. package/public/assets/font-awesome/less/larger.less +0 -13
  250. package/public/assets/font-awesome/less/list.less +0 -19
  251. package/public/assets/font-awesome/less/mixins.less +0 -60
  252. package/public/assets/font-awesome/less/path.less +0 -15
  253. package/public/assets/font-awesome/less/rotated-flipped.less +0 -20
  254. package/public/assets/font-awesome/less/screen-reader.less +0 -5
  255. package/public/assets/font-awesome/less/stacked.less +0 -20
  256. package/public/assets/font-awesome/less/variables.less +0 -800
  257. package/public/assets/font-awesome/scss/_animated.scss +0 -34
  258. package/public/assets/font-awesome/scss/_bordered-pulled.scss +0 -25
  259. package/public/assets/font-awesome/scss/_core.scss +0 -12
  260. package/public/assets/font-awesome/scss/_fixed-width.scss +0 -6
  261. package/public/assets/font-awesome/scss/_icons.scss +0 -789
  262. package/public/assets/font-awesome/scss/_larger.scss +0 -13
  263. package/public/assets/font-awesome/scss/_list.scss +0 -19
  264. package/public/assets/font-awesome/scss/_mixins.scss +0 -60
  265. package/public/assets/font-awesome/scss/_path.scss +0 -15
  266. package/public/assets/font-awesome/scss/_rotated-flipped.scss +0 -20
  267. package/public/assets/font-awesome/scss/_screen-reader.scss +0 -5
  268. package/public/assets/font-awesome/scss/_stacked.scss +0 -20
  269. package/public/assets/font-awesome/scss/_variables.scss +0 -800
  270. package/public/assets/font-awesome/scss/font-awesome.scss +0 -18
  271. package/public/main-es2018.625fb92c9cbb6a4131de.js +0 -1
  272. package/public/main-es5.625fb92c9cbb6a4131de.js +0 -1
  273. package/public/polyfills-es2018.713f95af1f028e444854.js +0 -1
  274. package/public/polyfills-es5.c78877945523541d2597.js +0 -1
  275. package/public/runtime-es2018.a4dadbc03350107420a4.js +0 -1
  276. package/public/runtime-es5.a4dadbc03350107420a4.js +0 -1
  277. package/public/styles.71bb0d04cad96b5efbe1.css +0 -19
  278. package/src/assets/font-awesome/HELP-US-OUT.txt +0 -7
  279. package/src/assets/font-awesome/css/font-awesome.css +0 -2337
  280. package/src/assets/font-awesome/css/font-awesome.min.css +0 -4
  281. package/src/assets/font-awesome/desktop.ini +0 -4
  282. package/src/assets/font-awesome/fonts/FontAwesome.otf +0 -0
  283. package/src/assets/font-awesome/fonts/fontawesome-webfont.eot +0 -0
  284. package/src/assets/font-awesome/fonts/fontawesome-webfont.svg +0 -2671
  285. package/src/assets/font-awesome/fonts/fontawesome-webfont.ttf +0 -0
  286. package/src/assets/font-awesome/fonts/fontawesome-webfont.woff +0 -0
  287. package/src/assets/font-awesome/fonts/fontawesome-webfont.woff2 +0 -0
  288. package/src/assets/font-awesome/less/animated.less +0 -34
  289. package/src/assets/font-awesome/less/bordered-pulled.less +0 -25
  290. package/src/assets/font-awesome/less/core.less +0 -12
  291. package/src/assets/font-awesome/less/fixed-width.less +0 -6
  292. package/src/assets/font-awesome/less/font-awesome.less +0 -18
  293. package/src/assets/font-awesome/less/icons.less +0 -789
  294. package/src/assets/font-awesome/less/larger.less +0 -13
  295. package/src/assets/font-awesome/less/list.less +0 -19
  296. package/src/assets/font-awesome/less/mixins.less +0 -60
  297. package/src/assets/font-awesome/less/path.less +0 -15
  298. package/src/assets/font-awesome/less/rotated-flipped.less +0 -20
  299. package/src/assets/font-awesome/less/screen-reader.less +0 -5
  300. package/src/assets/font-awesome/less/stacked.less +0 -20
  301. package/src/assets/font-awesome/less/variables.less +0 -800
  302. package/src/assets/font-awesome/scss/_animated.scss +0 -34
  303. package/src/assets/font-awesome/scss/_bordered-pulled.scss +0 -25
  304. package/src/assets/font-awesome/scss/_core.scss +0 -12
  305. package/src/assets/font-awesome/scss/_fixed-width.scss +0 -6
  306. package/src/assets/font-awesome/scss/_icons.scss +0 -789
  307. package/src/assets/font-awesome/scss/_larger.scss +0 -13
  308. package/src/assets/font-awesome/scss/_list.scss +0 -19
  309. package/src/assets/font-awesome/scss/_mixins.scss +0 -60
  310. package/src/assets/font-awesome/scss/_path.scss +0 -15
  311. package/src/assets/font-awesome/scss/_rotated-flipped.scss +0 -20
  312. package/src/assets/font-awesome/scss/_screen-reader.scss +0 -5
  313. package/src/assets/font-awesome/scss/_stacked.scss +0 -20
  314. package/src/assets/font-awesome/scss/_variables.scss +0 -800
  315. package/src/assets/font-awesome/scss/font-awesome.scss +0 -18
@@ -1,781 +1,774 @@
1
- import { ViewChild, Input, ElementRef, Component, OnInit, OnDestroy } from '@angular/core';
2
- import { Subscription } from 'rxjs';
3
- import { MatButton } from '@angular/material/button';
4
- import { MatDialog } from '@angular/material/dialog';
5
-
6
- import { SignalKService } from '../signalk.service';
7
- import { SignalkRequestsService, skRequest } from '../signalk-requests.service';
8
- import { ModalWidgetComponent } from '../modal-widget/modal-widget.component';
9
- import { WidgetManagerService, IWidget, IWidgetConfig } from '../widget-manager.service';
10
- import { UnitsService } from '../units.service';
11
-
12
-
13
- const defaultConfig: IWidgetConfig = {
14
- displayName: 'N2k Autopilot',
15
- filterSelfPaths: true,
16
- paths: {
17
- "apState": {
18
- description: "Autopilot State",
19
- path: 'self.steering.autopilot.state',
20
- source: 'default',
21
- pathType: "string",
22
- isPathConfigurable: false,
23
- convertUnitTo: "",
24
- },
25
- "apTargetHeadingMag": {
26
- description: "Autopilot Target Heading Mag",
27
- path: 'self.steering.autopilot.target.headingMagnetic',
28
- source: 'default',
29
- pathType: "number",
30
- convertUnitTo: "deg",
31
- isPathConfigurable: true,
32
- },
33
- "apTargetWindAngleApp": {
34
- description: "Autopilot Target Wind Angle Apparent",
35
- path: 'self.steering.autopilot.target.windAngleApparent',
36
- source: 'default',
37
- pathType: "number",
38
- convertUnitTo: "deg",
39
- isPathConfigurable: true,
40
- },
41
- "apNotifications": {
42
- description: "Autopilot Notifications",
43
- path: 'self.notifications.autopilot.*', //TODO(David): need to add support for .* type subscription paths in sk service and widget config modal
44
- source: 'default',
45
- pathType: "string",
46
- convertUnitTo: "",
47
- isPathConfigurable: false,
48
- },
49
- "headingMag": {
50
- description: "Heading Magnetic",
51
- path: 'self.navigation.headingMagnetic',
52
- source: 'default',
53
- pathType: "number",
54
- convertUnitTo: "deg",
55
- isPathConfigurable: true,
56
- },
57
- "headingTrue": {
58
- description: "Heading True",
59
- path: 'self.navigation.headingTrue',
60
- source: 'default',
61
- pathType: "number",
62
- convertUnitTo: "deg",
63
- isPathConfigurable: true,
64
- },
65
- "windAngleApparent": {
66
- description: "Wind Angle Apparent",
67
- path: 'self.environment.wind.angleApparent',
68
- source: 'default',
69
- pathType: "number",
70
- convertUnitTo: "deg",
71
- isPathConfigurable: true,
72
- },
73
- "windAngleTrueWater": {
74
- description: "Wind Angle True Water",
75
- path: 'self.environment.wind.angleTrueWater',
76
- source: 'default',
77
- pathType: "number",
78
- convertUnitTo: "deg",
79
- isPathConfigurable: true,
80
- },
81
- "rudderAngle": {
82
- description: "Rudder Angle",
83
- path: 'self.steering.rudderAngle',
84
- source: 'default',
85
- pathType: "number",
86
- convertUnitTo: "deg",
87
- isPathConfigurable: true,
88
- },
89
- },
90
- usage: {
91
- "headingMag": ['wind', 'route', 'auto', 'standby'],
92
- "headingTrue": ['wind', 'route', 'auto', 'standby'],
93
- "windAngleApparent": ['wind'],
94
- "windAngleTrueWater": ['wind'],
95
- },
96
- typeVal: {
97
- "headingMag": 'Mag',
98
- "headingTrue": 'True',
99
- "windAngleApparent": 'AWA',
100
- "windAngleTrueWater": 'TWA',
101
- },
102
- barColor: 'accent', // theme palette to select
103
- autoStart: false,
104
- };
105
-
106
- const defaultPpreferedDisplayMode = {
107
- wind: 'windAngleApparent',
108
- route: 'headingMag',
109
- auto: 'headingMag',
110
- standby: 'headingMag'
111
- }
112
-
113
- const commands = {
114
- "auto": {"path":"self.steering.autopilot.state","value":"auto"},
115
- "wind": {"path":"self.steering.autopilot.state","value":"wind"},
116
- "route": {"path":"self.steering.autopilot.state","value":"route"},
117
- "standby": {"path":"self.steering.autopilot.state","value":"standby"},
118
- "+1": {"path":"self.steering.autopilot.actions.adjustHeading","value":1},
119
- "+10": {"path":"self.steering.autopilot.actions.adjustHeading","value":10},
120
- "-1": {"path":"self.steering.autopilot.actions.adjustHeading","value":-1},
121
- "-10": {"path":"self.steering.autopilot.actions.adjustHeading","value":-10},
122
- "tackToPort": {"path":"self.steering.autopilot.actions.tack","value":"port"},
123
- "tackToStarboard": {"path":"self.steering.autopilot.actions.tack","value":"starboard"},
124
- "advanceWaypoint": {"path":"self.steering.autopilot.actions.advanceWaypoint","value":"1"}
125
- };
126
-
127
- const noData = '-- -- -- --';
128
- const noPilot = 'No pilot';
129
- const noHeading = '---°';
130
- const countDownDefault: number = 5;
131
- const timeoutBlink = 250;
132
-
133
- @Component({
134
- selector: 'app-widget-autopilot',
135
- templateUrl: './widget-autopilot.component.html',
136
- styleUrls: ['./widget-autopilot.component.scss'],
137
- })
138
- export class WidgetAutopilotComponent implements OnInit, OnDestroy {
139
- @Input('widgetUUID') widgetUUID: string;
140
- @Input('unlockStatus') unlockStatus: boolean;
141
-
142
- // AP keypad
143
- @ViewChild('powerBtn') powerBtn: MatButton;
144
- @ViewChild('stbTackBtn') stbTackBtn: MatButton;
145
- @ViewChild('plus1Btn') plus1Btn: MatButton;
146
- @ViewChild('minus1Btn') minus1Btn: MatButton;
147
- @ViewChild('prtTackBtn') prtTackBtn: MatButton;
148
- @ViewChild('standbyBtn') standbyBtn: MatButton;
149
- @ViewChild('plus10Btn') plus10Btn: MatButton;
150
- @ViewChild('minus10Btn') minus10Btn: MatButton;
151
- @ViewChild('autoBtn') autoBtn: MatButton;
152
- @ViewChild('windModeBtn') windModeBtn: MatButton;
153
- @ViewChild('trackModeBtn') trackModeBtn: MatButton;
154
- @ViewChild('nxtWpBtn') nxtWpBtn: MatButton;
155
- @ViewChild('muteBtn') muteBtn: MatButton;
156
- @ViewChild('messageBtn') messageBtn: MatButton;
157
-
158
- // AP Screen
159
- @ViewChild('appSvgAutopilot') apScreen : any;
160
-
161
- // hack to access material-theme palette colors
162
- @ViewChild('primary') private primaryElement: ElementRef;
163
- @ViewChild('accent') private accentElement: ElementRef;
164
- @ViewChild('warn') private warnElement: ElementRef;
165
- @ViewChild('primaryDark') private primaryDarkElement: ElementRef;
166
- @ViewChild('accentDark') private accentDarkElement: ElementRef;
167
- @ViewChild('warnDark') private warnDarkElement: ElementRef;
168
- @ViewChild('background') private backgroundElement: ElementRef;
169
- @ViewChild('text') private textElement: ElementRef;
170
-
171
- activeWidget: IWidget;
172
- config: IWidgetConfig;
173
- displayName: string;
174
-
175
- // Subscription stuff
176
- currentAPState: any = null; // Current Pilot Mode - used for display, keyboard state and buildCommand function
177
- apStateSub: Subscription = null;
178
-
179
- currentAPTargetAppWind: number = 0;
180
- apTargetAppWindSub: Subscription = null;
181
-
182
- currentHeading: number = 0;
183
- headingSub: Subscription = null;
184
-
185
- currentAppWindAngle: number = null;
186
- appWindAngleSub: Subscription = null;
187
-
188
- currentRudder: number = null;
189
- rudderSub: Subscription = null;
190
-
191
- skApNotificationSub = new Subscription;
192
- skRequestSub = new Subscription; // signalk-Request result observer
193
-
194
- // Widget var
195
- handleCountDownCounterTimeout = null;
196
- handleConfirmActionTimeout = null;
197
- handleMessageTimeout = null;
198
- handleReceiveTimeout = null;
199
- handleDisplayErrorTimeout = null;
200
- countDownValue: number = 0;
201
- actionToBeConfirmed: string = "";
202
- skPathToAck: string = "";
203
- preferedDisplayMode = defaultPpreferedDisplayMode;
204
- isWChecked: boolean = false; // used for Wind toggle
205
- isTChecked: boolean = false; // used for Track toggle
206
- isApConnected: boolean = false;
207
- notificationsArray = {};
208
- alarmsCount: number = 0;
209
-
210
- notificationTest = {};
211
-
212
- constructor(
213
- public dialog:MatDialog,
214
- private SignalKService: SignalKService,
215
- private SignalkRequestsService: SignalkRequestsService,
216
- private WidgetManagerService: WidgetManagerService,
217
- private UnitsService: UnitsService,
218
- ) { }
219
-
220
- ngOnInit() {
221
- this.activeWidget = this.WidgetManagerService.getWidget(this.widgetUUID);
222
- if (this.activeWidget.config === null) {
223
- // no data, let's set some!
224
- this.WidgetManagerService.updateWidgetConfig(this.widgetUUID, defaultConfig);
225
- this.config = defaultConfig; // load default config.
226
- } else {
227
- this.config = this.activeWidget.config;
228
- this.displayName = this.config.displayName;
229
- }
230
- if (this.config.autoStart) {
231
- setTimeout(() => {this.startApHead();});
232
- }
233
- // this.demoMode(); // demo mode for troubleshooting
234
- }
235
-
236
- demoMode() {
237
-
238
- // this.setNotificationMessage('{"path":"notifications.autopilot.PilotWarningWindShift","value":{"state":"alarm","message":"Pilot Warning Wind Shift"}}');
239
- }
240
-
241
- ngOnDestroy() {
242
- this.stopAllSubscriptions();
243
- }
244
-
245
- startAllSubscriptions() {
246
- this.subscribeHeading();
247
- this.subscribeAppWindAngle();
248
- this.subscribeRudder();
249
- this.subscribeAPState();
250
- this.subscribeAPTargetAppWind();
251
- this.subscribeSKRequest();
252
- this.subscribeAPNotification();
253
- console.log("Autopilot Sub Started");
254
- }
255
-
256
- stopAllSubscriptions() {
257
- this.unsubscribeHeading();
258
- this.unsubscribeAppWindAngle();
259
- this.unsubscribeRudder();
260
- this.unsubscribeAPState();
261
- this.unsubscribeAPTargetAppWind();
262
- this.unsubscribeSKRequest();
263
- this.unsubscribeAPNotification();
264
- console.log("Autopilot Subs Stopped");
265
- }
266
-
267
- subscribeAPNotification() {
268
- if (typeof(this.config.paths['apNotifications'].path) != 'string') { return } // nothing to sub to...
269
- this.skApNotificationSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['apNotifications'].path, this.config.paths['apNotifications'].source).subscribe(
270
- newValue => {
271
-
272
- if (!newValue.value == null) {
273
- this.setNotificationMessage(newValue.value);
274
- console.log(newValue.value);
275
- }
276
- }
277
- );
278
- }
279
-
280
- unsubscribeAPNotification() {
281
- if (this.skApNotificationSub !== null) {
282
- this.skApNotificationSub.unsubscribe();
283
- this.skApNotificationSub = null;
284
- this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['apNotifications'].path);
285
- }
286
- }
287
-
288
- subscribeSKRequest() {
289
- this.skRequestSub = this.SignalkRequestsService.subscribeRequest().subscribe(requestResult => {
290
- if (requestResult.widgetUUID == this.widgetUUID) {
291
- this.commandReceived(requestResult);
292
- }
293
- });
294
- }
295
-
296
- unsubscribeSKRequest() {
297
- if (this.skRequestSub !== null) {
298
- this.skRequestSub.unsubscribe();
299
- this.skRequestSub = null;
300
- }
301
- }
302
-
303
- subscribeAPTargetAppWind() {
304
- this.unsubscribeAPTargetAppWind();
305
- if (typeof(this.config.paths['apTargetWindAngleApp'].path) != 'string') { return } // nothing to sub to...
306
- this.apTargetAppWindSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['apTargetWindAngleApp'].path, this.config.paths['apTargetWindAngleApp'].source).subscribe(
307
- newValue => {
308
- if (newValue.value === null) {
309
- this.currentAPTargetAppWind = 0;
310
- } else {
311
- this.currentAPTargetAppWind = this.UnitsService.convertUnit('deg', newValue.value);
312
- }
313
- }
314
- );
315
- }
316
-
317
- unsubscribeAPTargetAppWind() {
318
- if (this.apTargetAppWindSub !== null) {
319
- this.apTargetAppWindSub.unsubscribe();
320
- this.apTargetAppWindSub = null;
321
- this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['apTargetWindAngleApp'].path);
322
- }
323
- }
324
-
325
- subscribeAPState() {
326
- if (typeof(this.config.paths['apState'].path) != 'string') { return } // nothing to sub to...
327
- this.apStateSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['apState'].path, this.config.paths['apState'].source).subscribe(
328
- newValue => {
329
- this.currentAPState = newValue.value;
330
- this.SetKeyboardMode(this.currentAPState);
331
- }
332
- );
333
- }
334
-
335
- unsubscribeAPState() {
336
- if (this.apStateSub !== null) {
337
- this.apStateSub.unsubscribe();
338
- this.apStateSub = null;
339
- this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['apState'].path);
340
- }
341
- }
342
-
343
- subscribeHeading() {
344
- this.unsubscribeHeading();
345
- if (typeof(this.config.paths['headingMag'].path) != 'string') { return } // nothing to sub to...
346
- this.headingSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['headingMag'].path, this.config.paths['headingMag'].source).subscribe(
347
- newValue => {
348
- if (newValue.value === null) {
349
- this.currentHeading = 0;
350
- } else {
351
-
352
- this.currentHeading = this.UnitsService.convertUnit('deg', newValue.value);
353
- }
354
-
355
- }
356
- );
357
- }
358
-
359
- unsubscribeHeading() {
360
- if (this.headingSub !== null) {
361
- this.headingSub.unsubscribe();
362
- this.headingSub = null;
363
- this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['headingMag'].path);
364
- }
365
- }
366
-
367
- subscribeAppWindAngle() {
368
- this.unsubscribeAppWindAngle();
369
- if (typeof(this.config.paths['windAngleApparent'].path) != 'string') { return } // nothing to sub to...
370
-
371
- this.appWindAngleSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['windAngleApparent'].path, this.config.paths['windAngleApparent'].source).subscribe(
372
- newValue => {
373
- if (newValue.value === null) {
374
- this.currentAppWindAngle = null;
375
- return;
376
- }
377
-
378
- let converted = this.UnitsService.convertUnit('deg', newValue.value);
379
- // 0-180+ for stb
380
- // -0 to -180 for port
381
- // need in 0-360
382
-
383
- if (converted < 0) {// stb
384
- this.currentAppWindAngle = 360 + converted; // adding a negative number subtracts it...
385
- } else {
386
- this.currentAppWindAngle = converted;
387
- }
388
- }
389
- );
390
- }
391
-
392
- unsubscribeAppWindAngle() {
393
- if (this.appWindAngleSub !== null) {
394
- this.appWindAngleSub.unsubscribe();
395
- this.appWindAngleSub = null;
396
- this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['windAngleApparent'].path);
397
- }
398
- }
399
-
400
- subscribeRudder() {
401
- this.unsubscribeRudder();
402
- if (typeof(this.config.paths['rudderAngle'].path) != 'string') { return } // nothing to sub to...
403
- this.rudderSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['rudderAngle'].path, this.config.paths['rudderAngle'].source).subscribe(
404
- newValue => {
405
- if (newValue.value === null) {
406
- this.currentRudder = 0;
407
- } else {
408
-
409
- this.currentRudder = this.UnitsService.convertUnit('deg', newValue.value);
410
- }
411
-
412
- }
413
- );
414
- }
415
-
416
- unsubscribeRudder() {
417
- if (this.rudderSub !== null) {
418
- this.rudderSub.unsubscribe();
419
- this.rudderSub = null;
420
- this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['rudderAngle'].path);
421
- }
422
- }
423
-
424
- openWidgetSettings() {
425
- let dialogRef = this.dialog.open(ModalWidgetComponent, {
426
- width: '80%',
427
- data: this.config
428
- });
429
-
430
- dialogRef.afterClosed().subscribe(result => {
431
- // save new settings
432
- if (result) {
433
- this.config = result;
434
- this.displayName = this.config.displayName;
435
- console.log(result);
436
- this.WidgetManagerService.updateWidgetConfig(this.widgetUUID, this.config);
437
-
438
- if (this.isApConnected) {
439
- this.stopAllSubscriptions();
440
- this.startAllSubscriptions();
441
- }
442
- }
443
- });
444
- }
445
-
446
- addHeading(h1: number, h2: number) {
447
- let h3 = h1 + h2;
448
- while (h3 > 359) { h3 = h3 - 359; }
449
- while (h3 < 0) { h3 = h3 + 359; }
450
- return h3;
451
- }
452
-
453
- powerBtnClick(event: Event) {
454
- if (!this.isApConnected) {
455
- this.startApHead();
456
- } else {
457
- this.stopApHead();
458
- }
459
- }
460
-
461
- startApHead() {
462
- this.startAllSubscriptions();
463
- this.config.autoStart = true; // save power-on state to autostart or not
464
- this.WidgetManagerService.updateWidgetConfig(this.widgetUUID, this.config);
465
-
466
- this.isApConnected = true;
467
- this.muteBtn.disabled = true;
468
- this.messageBtn.disabled = false;
469
- }
470
-
471
- stopApHead() {
472
- this.muteBtn.disabled = true;
473
- this.messageBtn.disabled = true;
474
- this.windModeBtn.disabled = true;
475
- this.trackModeBtn.disabled = true;
476
- this.nxtWpBtn.disabled = true;
477
- this.autoBtn.disabled = true;
478
- this.standbyBtn.disabled = true;
479
- this.plus1Btn.disabled = true;
480
- this.plus10Btn.disabled = true;
481
- this.minus1Btn.disabled = true;
482
- this.minus10Btn.disabled = true;
483
- this.prtTackBtn.disabled = true;
484
- this.stbTackBtn.disabled = true;
485
-
486
- this.apScreen.errorIconVisibility = 'hidden';
487
-
488
- this.isApConnected = false; // hide ap screen
489
- this.stopAllSubscriptions();
490
- this.config.autoStart = false; // save power on state to autostart or not
491
- this.WidgetManagerService.updateWidgetConfig(this.widgetUUID, this.config);
492
- }
493
-
494
- SetKeyboardMode(apMode: string) {
495
- switch (apMode) {
496
- case "standby":
497
- this.trackModeBtn.disabled = false;
498
- this.nxtWpBtn.disabled = true;
499
- this.autoBtn.disabled = false;
500
- this.standbyBtn.disabled = false;
501
-
502
- this.windModeBtn.disabled = false;
503
- this.plus1Btn.disabled = true;
504
- this.plus10Btn.disabled = true;
505
- this.minus1Btn.disabled = true;
506
- this.minus10Btn.disabled = true;
507
- this.prtTackBtn.disabled = true;
508
- this.stbTackBtn.disabled = true;
509
- break;
510
-
511
- case "auto":
512
- this.trackModeBtn.disabled = false;
513
- this.nxtWpBtn.disabled = true;
514
- this.autoBtn.disabled = false;
515
- this.standbyBtn.disabled = false;
516
-
517
- this.windModeBtn.disabled = false;
518
- this.plus1Btn.disabled = false;
519
- this.plus10Btn.disabled = false;
520
- this.minus1Btn.disabled = false;
521
- this.minus10Btn.disabled = false;
522
- this.prtTackBtn.disabled = true;
523
- this.stbTackBtn.disabled = true;
524
- break;
525
-
526
- case "wind":
527
- this.trackModeBtn.disabled = true;
528
- this.nxtWpBtn.disabled = true;
529
- this.autoBtn.disabled = false;
530
- this.standbyBtn.disabled = false;
531
-
532
- this.windModeBtn.disabled = false;
533
- this.plus1Btn.disabled = false;
534
- this.plus10Btn.disabled = false;
535
- this.minus1Btn.disabled = false;
536
- this.minus10Btn.disabled = false;
537
- this.prtTackBtn.disabled = false;
538
- this.stbTackBtn.disabled = false;
539
- break;
540
-
541
- case "route":
542
- this.trackModeBtn.disabled = true;
543
- this.nxtWpBtn.disabled = false;
544
- this.autoBtn.disabled = false;
545
- this.standbyBtn.disabled = false;
546
-
547
- this.windModeBtn.disabled = true;
548
- this.plus1Btn.disabled = true;
549
- this.plus10Btn.disabled = true;
550
- this.minus1Btn.disabled = true;
551
- this.minus10Btn.disabled = true;
552
- this.prtTackBtn.disabled = true;
553
- this.stbTackBtn.disabled = true;
554
- break;
555
-
556
- default:
557
- break;
558
- }
559
- }
560
-
561
- buildAndSendCommand(cmd: string) {
562
- let cmdAction = commands[cmd];
563
- if (typeof cmdAction === 'undefined') {
564
- alert('Unknown Autopilot command: ' + cmd);
565
- return null;
566
- }
567
- if ((this.actionToBeConfirmed !== '')&&(this.actionToBeConfirmed !== cmd)) {
568
- this.clearConfirmCmd();
569
- }
570
- if (((cmd === 'tackToPort')||(cmd === 'tackToStarboard'))&&(this.actionToBeConfirmed === '')) {
571
- this.confirmTack(cmd);
572
- return null;
573
- }
574
- if ((cmd === 'route')&&(this.currentAPState === 'route')&&(this.actionToBeConfirmed === '')) {
575
- this.confirmAdvanceWaypoint(cmd);
576
- return null;
577
- }
578
- if (this.actionToBeConfirmed === cmd) {
579
- this.clearConfirmCmd();
580
- if ((cmd === 'tackToPort')||(cmd === 'tackToStarboard')) {
581
- this.sendCommand(commands['auto']); // force mode 'auto' to take a tack
582
- this.sendCommand(cmdAction);
583
- }
584
- if ((cmd === 'route')&&(this.currentAPState === 'route')) {
585
- this.sendCommand(commands['advanceWaypoint']);
586
- }
587
- return null;
588
- }
589
- this.sendCommand(cmdAction);
590
- }
591
-
592
- confirmAdvanceWaypoint(cmd: string) {
593
- let message: string = "Repeat key <b>[Next Wpt]</b><br>to confirm<br>Advance Waypoint";
594
- this.startConfirmCmd(cmd, message);
595
- }
596
-
597
- confirmTack(cmd: string) {
598
- let message = "Repeat same key<br>to confirm<br>tack to ";
599
- if (cmd === "tackToPort") {
600
- message += "port";
601
- this.actionToBeConfirmed = cmd;
602
- } else if (cmd === "tackToStarboard") {
603
- message += "starboard";
604
- this.actionToBeConfirmed = cmd;
605
- } else {
606
- this.actionToBeConfirmed = "";
607
- return null;
608
- }
609
- this.startConfirmCmd(cmd, message);
610
- }
611
-
612
- sendCommand(cmdAction) {
613
- let requestId = this.SignalkRequestsService.putRequest(cmdAction["path"], cmdAction["value"], this.widgetUUID);
614
- this.apScreen.activityIconVisibility = "visible";
615
- setTimeout(() => {this.apScreen.activityIconVisibility = 'hidden';}, timeoutBlink);
616
-
617
- console.log("AP Action:\n" + JSON.stringify(cmdAction));
618
- }
619
-
620
- commandReceived(cmdResult: skRequest) {
621
- this.apScreen.activityIconVisibility = "visible";
622
- clearTimeout(this.handleReceiveTimeout);
623
- this.handleReceiveTimeout = setTimeout(() => {this.apScreen.activityIconVisibility = 'hidden';}, timeoutBlink);
624
-
625
- if (cmdResult.statusCode != 200){
626
- this.displayApError(cmdResult);
627
- } else {
628
- console.log("AP Received: \n" + JSON.stringify(cmdResult));
629
- }
630
- }
631
-
632
- startConfirmCmd(cmd: string, message: string) {
633
- this.countDownValue = countDownDefault;
634
- this.actionToBeConfirmed = cmd;
635
-
636
- this.apScreen.msgStencilInnerHTML = "<p>" + message + "</p>";
637
- this.apScreen.msgStencilVisibility = "visible";
638
-
639
- this.updateCountDownCounter(message);
640
-
641
- clearTimeout(this.handleConfirmActionTimeout);
642
-
643
- this.handleConfirmActionTimeout = setTimeout(() => {
644
- this.apScreen.msgStencilVisibility = "hidden";
645
- this.apScreen.msgStencilInnerHTML = "";
646
- this.actionToBeConfirmed = "";
647
- }, 5000);
648
- }
649
-
650
- clearConfirmCmd() : boolean {
651
- clearTimeout(this.handleConfirmActionTimeout);
652
- clearTimeout(this.handleCountDownCounterTimeout);
653
- this.countDownValue = -1;
654
- this.apScreen.msgStencilVisibility = "hidden";
655
- this.apScreen.msgStencilInnerHTML = "";
656
- this.actionToBeConfirmed = '';
657
- return null;
658
- }
659
-
660
- updateCountDownCounter(message: string) {
661
- if (this.countDownValue > 0) {
662
- clearTimeout(this.handleCountDownCounterTimeout);
663
- this.apScreen.msgStencilInnerHTML = "<p>" + message + "</p>" + "<h1 class='counterText'>" + this.countDownValue.toString() + "</h1>";
664
- this.countDownValue -= 1;
665
- this.handleCountDownCounterTimeout = setTimeout(() => {
666
- this.updateCountDownCounter(message);
667
- }, 1000);
668
- } else {
669
- clearTimeout(this.handleCountDownCounterTimeout);
670
- }
671
- }
672
-
673
- displayApError(cmdResult: skRequest) {
674
- let errMsg = cmdResult.statusCode + " - " +cmdResult.statusCodeDescription;
675
- if (cmdResult.message){
676
- errMsg = errMsg + " Server Message: " + cmdResult.message;
677
- }
678
- this.apScreen.errorStencilInnerText = errMsg;
679
- this.apScreen.errorStencilVisibility = "visible";
680
-
681
- clearTimeout(this.handleDisplayErrorTimeout);
682
-
683
- this.handleDisplayErrorTimeout = setTimeout(() => {
684
- this.apScreen.errorStencilVisibility = "hidden";
685
- this.apScreen.errorStencilInnerText = "";
686
- }, 6000);
687
- this.apScreen.errorIconVisibility = 'visible';
688
- }
689
-
690
- getNextNotification(skPath: string): string {
691
- let notificationsKeys = Object.keys(this.notificationsArray);
692
- let newSkPathToAck: string = "";
693
- let index: number = 0;
694
- if (notificationsKeys.length > 0) {
695
- if (typeof skPath !== "undefined") {
696
- index = notificationsKeys.indexOf(skPath) + 1;
697
- } else {
698
- index = 0;
699
- }
700
- if (notificationsKeys.length <= index) {
701
- index = 0;
702
- }
703
- newSkPathToAck = notificationsKeys[index];
704
- }
705
- return newSkPathToAck;
706
- }
707
-
708
- setNotificationMessage(value) {
709
- this.apScreen.activityIconVisibility = "visible";
710
- clearTimeout(this.handleReceiveTimeout);
711
- this.handleReceiveTimeout = setTimeout(() => {this.apScreen.activityIconVisibility = 'hidden';}, timeoutBlink);
712
-
713
- if (typeof value.path !== 'undefined') {
714
- value.path = value.path.replace('notifications.', '');
715
- if (typeof value.value !== 'undefined') {
716
- if (value.value.state === 'normal') {
717
- if (this.apScreen.messageInnerText === this.notificationsArray[value.path]) {
718
- this.apScreen.messageInnerText = '';
719
- }
720
- delete this.notificationsArray[value.path]
721
- } else {
722
- this.notificationsArray[value.path] = value.value.message.replace("Pilot", "");
723
- this.apScreen.messageInnerText = this.notificationsArray[value.path];
724
- }
725
- }
726
- }
727
- this.alarmsCount = Object.keys(this.notificationsArray).length;
728
- if (this.alarmsCount > 0) {
729
- this.muteBtn.disabled = false;
730
- if (this.apScreen.messageInnerText == "") {
731
- this.apScreen.messageInnerText = Object.keys(this.notificationsArray)[0];
732
- }
733
- } else {
734
- this.muteBtn.disabled = true;
735
- this.alarmsCount = 0;
736
- this.apScreen.messageInnerText = "";
737
- }
738
- }
739
-
740
- notificationToValue(skPathToAck: string): string {
741
- let message: string = this.notificationsArray[skPathToAck];
742
- if (typeof message == "undefined") {
743
- message = "No alarm present...";
744
- }
745
- return message;
746
- }
747
-
748
- notificationScroll() {
749
- if ((Object.keys(this.notificationsArray).length > 0) && (this.skPathToAck == "")) {
750
- this.skPathToAck = Object.keys(this.notificationsArray)[0];
751
- }
752
-
753
- this.skPathToAck = this.getNextNotification(this.skPathToAck);
754
- // Not sure about this DIV ??? May be message area???
755
- // silenceScreenTextDiv.innerHTML = notificationToValue(skPathToAck);
756
- this.apScreen.messageInnerText = this.notificationToValue(this.skPathToAck);
757
- this.apScreen.messageVisibility = 'visible';
758
- clearTimeout(this.handleMessageTimeout);
759
- this.handleMessageTimeout = setTimeout(() => {
760
- this.apScreen.messageInnerText = "";
761
- this.apScreen.messageVisibility = 'hidden';
762
- }, 2000);
763
- }
764
-
765
- sendSilence() {
766
- if (this.apScreen.messageVisibility != 'visible') {
767
- this.apScreen.messageVisibility = 'visible';
768
-
769
- if ((Object.keys(this.notificationsArray).length > 0) && (this.skPathToAck == "")) {
770
- this.skPathToAck = Object.keys(this.notificationsArray)[0];
771
- }
772
- } else {
773
- if (this.skPathToAck !== "") {
774
- this.sendCommand({"path":"notifications." + this.skPathToAck + ".state","value":"normal"});
775
- // this.sendCommand({"path":"notifications." + skPathToAck + ".method","value":[]});
776
- }
777
- this.apScreen.messageVisibility = 'hidden';
778
- }
779
- this.apScreen.messageInnerText = this.notificationToValue(this.skPathToAck);
780
- }
781
- }
1
+ import { ViewChild, Input, ElementRef, Component, OnInit, OnDestroy } from '@angular/core';
2
+ import { Subscription } from 'rxjs';
3
+ import { MatButton } from '@angular/material/button';
4
+ import { MatDialog } from '@angular/material/dialog';
5
+
6
+ import { SignalKService } from '../signalk.service';
7
+ import { SignalkRequestsService, skRequest } from '../signalk-requests.service';
8
+ import { ModalWidgetComponent } from '../modal-widget/modal-widget.component';
9
+ import { WidgetManagerService, IWidget, IWidgetConfig } from '../widget-manager.service';
10
+ import { UnitsService } from '../units.service';
11
+
12
+
13
+ const defaultConfig: IWidgetConfig = {
14
+ displayName: 'N2k Autopilot',
15
+ filterSelfPaths: true,
16
+ paths: {
17
+ "apState": {
18
+ description: "Autopilot State",
19
+ path: 'self.steering.autopilot.state',
20
+ source: 'default',
21
+ pathType: "string",
22
+ isPathConfigurable: false,
23
+ convertUnitTo: "",
24
+ },
25
+ "apTargetHeadingMag": {
26
+ description: "Autopilot Target Heading Mag",
27
+ path: 'self.steering.autopilot.target.headingMagnetic',
28
+ source: 'default',
29
+ pathType: "number",
30
+ convertUnitTo: "deg",
31
+ isPathConfigurable: true,
32
+ },
33
+ "apTargetWindAngleApp": {
34
+ description: "Autopilot Target Wind Angle Apparent",
35
+ path: 'self.steering.autopilot.target.windAngleApparent',
36
+ source: 'default',
37
+ pathType: "number",
38
+ convertUnitTo: "deg",
39
+ isPathConfigurable: true,
40
+ },
41
+ "apNotifications": {
42
+ description: "Autopilot Notifications",
43
+ path: 'self.notifications.autopilot.*', //TODO(David): need to add support for .* type subscription paths in sk service and widget config modal
44
+ source: 'default',
45
+ pathType: "string",
46
+ convertUnitTo: "",
47
+ isPathConfigurable: false,
48
+ },
49
+ "headingMag": {
50
+ description: "Heading Magnetic",
51
+ path: 'self.navigation.headingMagnetic',
52
+ source: 'default',
53
+ pathType: "number",
54
+ convertUnitTo: "deg",
55
+ isPathConfigurable: true,
56
+ },
57
+ "headingTrue": {
58
+ description: "Heading True",
59
+ path: 'self.navigation.headingTrue',
60
+ source: 'default',
61
+ pathType: "number",
62
+ convertUnitTo: "deg",
63
+ isPathConfigurable: true,
64
+ },
65
+ "windAngleApparent": {
66
+ description: "Wind Angle Apparent",
67
+ path: 'self.environment.wind.angleApparent',
68
+ source: 'default',
69
+ pathType: "number",
70
+ convertUnitTo: "deg",
71
+ isPathConfigurable: true,
72
+ },
73
+ "windAngleTrueWater": {
74
+ description: "Wind Angle True Water",
75
+ path: 'self.environment.wind.angleTrueWater',
76
+ source: 'default',
77
+ pathType: "number",
78
+ convertUnitTo: "deg",
79
+ isPathConfigurable: true,
80
+ },
81
+ "rudderAngle": {
82
+ description: "Rudder Angle",
83
+ path: 'self.steering.rudderAngle',
84
+ source: 'default',
85
+ pathType: "number",
86
+ convertUnitTo: "deg",
87
+ isPathConfigurable: true,
88
+ },
89
+ },
90
+ usage: {
91
+ "headingMag": ['wind', 'route', 'auto', 'standby'],
92
+ "headingTrue": ['wind', 'route', 'auto', 'standby'],
93
+ "windAngleApparent": ['wind'],
94
+ "windAngleTrueWater": ['wind'],
95
+ },
96
+ typeVal: {
97
+ "headingMag": 'Mag',
98
+ "headingTrue": 'True',
99
+ "windAngleApparent": 'AWA',
100
+ "windAngleTrueWater": 'TWA',
101
+ },
102
+ barColor: 'accent', // theme palette to select
103
+ autoStart: false,
104
+ };
105
+
106
+ const defaultPpreferedDisplayMode = {
107
+ wind: 'windAngleApparent',
108
+ route: 'headingMag',
109
+ auto: 'headingMag',
110
+ standby: 'headingMag'
111
+ }
112
+
113
+ const commands = {
114
+ "auto": {"path":"self.steering.autopilot.state","value":"auto"},
115
+ "wind": {"path":"self.steering.autopilot.state","value":"wind"},
116
+ "route": {"path":"self.steering.autopilot.state","value":"route"},
117
+ "standby": {"path":"self.steering.autopilot.state","value":"standby"},
118
+ "+1": {"path":"self.steering.autopilot.actions.adjustHeading","value":1},
119
+ "+10": {"path":"self.steering.autopilot.actions.adjustHeading","value":10},
120
+ "-1": {"path":"self.steering.autopilot.actions.adjustHeading","value":-1},
121
+ "-10": {"path":"self.steering.autopilot.actions.adjustHeading","value":-10},
122
+ "tackToPort": {"path":"self.steering.autopilot.actions.tack","value":"port"},
123
+ "tackToStarboard": {"path":"self.steering.autopilot.actions.tack","value":"starboard"},
124
+ "advanceWaypoint": {"path":"self.steering.autopilot.actions.advanceWaypoint","value":"1"}
125
+ };
126
+
127
+ const noData = '-- -- -- --';
128
+ const noPilot = 'No pilot';
129
+ const noHeading = '---&deg;';
130
+ const countDownDefault: number = 5;
131
+ const timeoutBlink = 250;
132
+
133
+ @Component({
134
+ selector: 'app-widget-autopilot',
135
+ templateUrl: './widget-autopilot.component.html',
136
+ styleUrls: ['./widget-autopilot.component.scss'],
137
+ })
138
+ export class WidgetAutopilotComponent implements OnInit, OnDestroy {
139
+ @Input('widgetUUID') widgetUUID: string;
140
+ @Input('unlockStatus') unlockStatus: boolean;
141
+
142
+ // AP keypad
143
+ @ViewChild('powerBtn') powerBtn: MatButton;
144
+ @ViewChild('stbTackBtn') stbTackBtn: MatButton;
145
+ @ViewChild('plus1Btn') plus1Btn: MatButton;
146
+ @ViewChild('minus1Btn') minus1Btn: MatButton;
147
+ @ViewChild('prtTackBtn') prtTackBtn: MatButton;
148
+ @ViewChild('standbyBtn') standbyBtn: MatButton;
149
+ @ViewChild('plus10Btn') plus10Btn: MatButton;
150
+ @ViewChild('minus10Btn') minus10Btn: MatButton;
151
+ @ViewChild('autoBtn') autoBtn: MatButton;
152
+ @ViewChild('windModeBtn') windModeBtn: MatButton;
153
+ @ViewChild('trackModeBtn') trackModeBtn: MatButton;
154
+ @ViewChild('muteBtn') muteBtn: MatButton;
155
+ @ViewChild('messageBtn') messageBtn: MatButton;
156
+
157
+ // AP Screen
158
+ @ViewChild('appSvgAutopilot') apScreen : any;
159
+
160
+ // hack to access material-theme palette colors
161
+ @ViewChild('primary') private primaryElement: ElementRef;
162
+ @ViewChild('accent') private accentElement: ElementRef;
163
+ @ViewChild('warn') private warnElement: ElementRef;
164
+ @ViewChild('primaryDark') private primaryDarkElement: ElementRef;
165
+ @ViewChild('accentDark') private accentDarkElement: ElementRef;
166
+ @ViewChild('warnDark') private warnDarkElement: ElementRef;
167
+ @ViewChild('background') private backgroundElement: ElementRef;
168
+ @ViewChild('text') private textElement: ElementRef;
169
+
170
+ activeWidget: IWidget;
171
+ config: IWidgetConfig;
172
+ displayName: string;
173
+
174
+ // Subscription stuff
175
+ currentAPState: any = null; // Current Pilot Mode - used for display, keyboard state and buildCommand function
176
+ apStateSub: Subscription = null;
177
+
178
+ currentAPTargetAppWind: number = 0;
179
+ apTargetAppWindSub: Subscription = null;
180
+
181
+ currentHeading: number = 0;
182
+ headingSub: Subscription = null;
183
+
184
+ currentAppWindAngle: number = null;
185
+ appWindAngleSub: Subscription = null;
186
+
187
+ currentRudder: number = null;
188
+ rudderSub: Subscription = null;
189
+
190
+ skApNotificationSub = new Subscription;
191
+ skRequestSub = new Subscription; // signalk-Request result observer
192
+
193
+ // Widget var
194
+ handleCountDownCounterTimeout = null;
195
+ handleConfirmActionTimeout = null;
196
+ handleMessageTimeout = null;
197
+ handleReceiveTimeout = null;
198
+ handleDisplayErrorTimeout = null;
199
+ countDownValue: number = 0;
200
+ actionToBeConfirmed: string = "";
201
+ skPathToAck: string = "";
202
+ preferedDisplayMode = defaultPpreferedDisplayMode;
203
+ isWChecked: boolean = false; // used for Wind toggle
204
+ isTChecked: boolean = false; // used for Track toggle
205
+ isApConnected: boolean = false;
206
+ notificationsArray = {};
207
+ alarmsCount: number = 0;
208
+
209
+ notificationTest = {};
210
+
211
+ constructor(
212
+ public dialog:MatDialog,
213
+ private SignalKService: SignalKService,
214
+ private SignalkRequestsService: SignalkRequestsService,
215
+ private WidgetManagerService: WidgetManagerService,
216
+ private UnitsService: UnitsService,
217
+ ) { }
218
+
219
+ ngOnInit() {
220
+ this.activeWidget = this.WidgetManagerService.getWidget(this.widgetUUID);
221
+ if (this.activeWidget.config === null) {
222
+ // no data, let's set some!
223
+ this.WidgetManagerService.updateWidgetConfig(this.widgetUUID, defaultConfig);
224
+ this.config = defaultConfig; // load default config.
225
+ } else {
226
+ this.config = this.activeWidget.config;
227
+ this.displayName = this.config.displayName;
228
+ }
229
+ if (this.config.autoStart) {
230
+ setTimeout(() => {this.startApHead();});
231
+ }
232
+ // this.demoMode(); // demo mode for troubleshooting
233
+ }
234
+
235
+ demoMode() {
236
+
237
+ // this.setNotificationMessage('{"path":"notifications.autopilot.PilotWarningWindShift","value":{"state":"alarm","message":"Pilot Warning Wind Shift"}}');
238
+ }
239
+
240
+ ngOnDestroy() {
241
+ this.stopAllSubscriptions();
242
+ }
243
+
244
+ startAllSubscriptions() {
245
+ this.subscribeHeading();
246
+ this.subscribeAppWindAngle();
247
+ this.subscribeRudder();
248
+ this.subscribeAPState();
249
+ this.subscribeAPTargetAppWind();
250
+ this.subscribeSKRequest();
251
+ this.subscribeAPNotification();
252
+ console.log("Autopilot Sub Started");
253
+ }
254
+
255
+ stopAllSubscriptions() {
256
+ this.unsubscribeHeading();
257
+ this.unsubscribeAppWindAngle();
258
+ this.unsubscribeRudder();
259
+ this.unsubscribeAPState();
260
+ this.unsubscribeAPTargetAppWind();
261
+ this.unsubscribeSKRequest();
262
+ this.unsubscribeAPNotification();
263
+ console.log("Autopilot Subs Stopped");
264
+ }
265
+
266
+ subscribeAPNotification() {
267
+ if (typeof(this.config.paths['apNotifications'].path) != 'string') { return } // nothing to sub to...
268
+ this.skApNotificationSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['apNotifications'].path, this.config.paths['apNotifications'].source).subscribe(
269
+ newValue => {
270
+
271
+ if (!newValue.value == null) {
272
+ this.setNotificationMessage(newValue.value);
273
+ console.log(newValue.value);
274
+ }
275
+ }
276
+ );
277
+ }
278
+
279
+ unsubscribeAPNotification() {
280
+ if (this.skApNotificationSub !== null) {
281
+ this.skApNotificationSub.unsubscribe();
282
+ this.skApNotificationSub = null;
283
+ this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['apNotifications'].path);
284
+ }
285
+ }
286
+
287
+ subscribeSKRequest() {
288
+ this.skRequestSub = this.SignalkRequestsService.subscribeRequest().subscribe(requestResult => {
289
+ if (requestResult.widgetUUID == this.widgetUUID) {
290
+ this.commandReceived(requestResult);
291
+ }
292
+ });
293
+ }
294
+
295
+ unsubscribeSKRequest() {
296
+ if (this.skRequestSub !== null) {
297
+ this.skRequestSub.unsubscribe();
298
+ this.skRequestSub = null;
299
+ }
300
+ }
301
+
302
+ subscribeAPTargetAppWind() {
303
+ this.unsubscribeAPTargetAppWind();
304
+ if (typeof(this.config.paths['apTargetWindAngleApp'].path) != 'string') { return } // nothing to sub to...
305
+ this.apTargetAppWindSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['apTargetWindAngleApp'].path, this.config.paths['apTargetWindAngleApp'].source).subscribe(
306
+ newValue => {
307
+ if (newValue.value === null) {
308
+ this.currentAPTargetAppWind = 0;
309
+ } else {
310
+ this.currentAPTargetAppWind = this.UnitsService.convertUnit('deg', newValue.value);
311
+ }
312
+ }
313
+ );
314
+ }
315
+
316
+ unsubscribeAPTargetAppWind() {
317
+ if (this.apTargetAppWindSub !== null) {
318
+ this.apTargetAppWindSub.unsubscribe();
319
+ this.apTargetAppWindSub = null;
320
+ this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['apTargetWindAngleApp'].path);
321
+ }
322
+ }
323
+
324
+ subscribeAPState() {
325
+ if (typeof(this.config.paths['apState'].path) != 'string') { return } // nothing to sub to...
326
+ this.apStateSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['apState'].path, this.config.paths['apState'].source).subscribe(
327
+ newValue => {
328
+ this.currentAPState = newValue.value;
329
+ this.SetKeyboardMode(this.currentAPState);
330
+ }
331
+ );
332
+ }
333
+
334
+ unsubscribeAPState() {
335
+ if (this.apStateSub !== null) {
336
+ this.apStateSub.unsubscribe();
337
+ this.apStateSub = null;
338
+ this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['apState'].path);
339
+ }
340
+ }
341
+
342
+ subscribeHeading() {
343
+ this.unsubscribeHeading();
344
+ if (typeof(this.config.paths['headingMag'].path) != 'string') { return } // nothing to sub to...
345
+ this.headingSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['headingMag'].path, this.config.paths['headingMag'].source).subscribe(
346
+ newValue => {
347
+ if (newValue.value === null) {
348
+ this.currentHeading = 0;
349
+ } else {
350
+
351
+ this.currentHeading = this.UnitsService.convertUnit('deg', newValue.value);
352
+ }
353
+
354
+ }
355
+ );
356
+ }
357
+
358
+ unsubscribeHeading() {
359
+ if (this.headingSub !== null) {
360
+ this.headingSub.unsubscribe();
361
+ this.headingSub = null;
362
+ this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['headingMag'].path);
363
+ }
364
+ }
365
+
366
+ subscribeAppWindAngle() {
367
+ this.unsubscribeAppWindAngle();
368
+ if (typeof(this.config.paths['windAngleApparent'].path) != 'string') { return } // nothing to sub to...
369
+
370
+ this.appWindAngleSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['windAngleApparent'].path, this.config.paths['windAngleApparent'].source).subscribe(
371
+ newValue => {
372
+ if (newValue.value === null) {
373
+ this.currentAppWindAngle = null;
374
+ return;
375
+ }
376
+
377
+ let converted = this.UnitsService.convertUnit('deg', newValue.value);
378
+ // 0-180+ for stb
379
+ // -0 to -180 for port
380
+ // need in 0-360
381
+
382
+ if (converted < 0) {// stb
383
+ this.currentAppWindAngle = 360 + converted; // adding a negative number subtracts it...
384
+ } else {
385
+ this.currentAppWindAngle = converted;
386
+ }
387
+ }
388
+ );
389
+ }
390
+
391
+ unsubscribeAppWindAngle() {
392
+ if (this.appWindAngleSub !== null) {
393
+ this.appWindAngleSub.unsubscribe();
394
+ this.appWindAngleSub = null;
395
+ this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['windAngleApparent'].path);
396
+ }
397
+ }
398
+
399
+ subscribeRudder() {
400
+ this.unsubscribeRudder();
401
+ if (typeof(this.config.paths['rudderAngle'].path) != 'string') { return } // nothing to sub to...
402
+ this.rudderSub = this.SignalKService.subscribePath(this.widgetUUID, this.config.paths['rudderAngle'].path, this.config.paths['rudderAngle'].source).subscribe(
403
+ newValue => {
404
+ if (newValue.value === null) {
405
+ this.currentRudder = 0;
406
+ } else {
407
+
408
+ this.currentRudder = this.UnitsService.convertUnit('deg', newValue.value);
409
+ }
410
+
411
+ }
412
+ );
413
+ }
414
+
415
+ unsubscribeRudder() {
416
+ if (this.rudderSub !== null) {
417
+ this.rudderSub.unsubscribe();
418
+ this.rudderSub = null;
419
+ this.SignalKService.unsubscribePath(this.widgetUUID, this.config.paths['rudderAngle'].path);
420
+ }
421
+ }
422
+
423
+ openWidgetSettings() {
424
+ let dialogRef = this.dialog.open(ModalWidgetComponent, {
425
+ width: '80%',
426
+ data: this.config
427
+ });
428
+
429
+ dialogRef.afterClosed().subscribe(result => {
430
+ // save new settings
431
+ if (result) {
432
+ this.config = result;
433
+ this.displayName = this.config.displayName;
434
+ console.log(result);
435
+ this.WidgetManagerService.updateWidgetConfig(this.widgetUUID, this.config);
436
+
437
+ if (this.isApConnected) {
438
+ this.stopAllSubscriptions();
439
+ this.startAllSubscriptions();
440
+ }
441
+ }
442
+ });
443
+ }
444
+
445
+ addHeading(h1: number, h2: number) {
446
+ let h3 = h1 + h2;
447
+ while (h3 > 359) { h3 = h3 - 359; }
448
+ while (h3 < 0) { h3 = h3 + 359; }
449
+ return h3;
450
+ }
451
+
452
+ powerBtnClick(event: Event) {
453
+ if (!this.isApConnected) {
454
+ this.startApHead();
455
+ } else {
456
+ this.stopApHead();
457
+ }
458
+ }
459
+
460
+ startApHead() {
461
+ this.startAllSubscriptions();
462
+ this.config.autoStart = true; // save power-on state to autostart or not
463
+ this.WidgetManagerService.updateWidgetConfig(this.widgetUUID, this.config);
464
+
465
+ this.isApConnected = true;
466
+ this.muteBtn.disabled = true;
467
+ this.messageBtn.disabled = false;
468
+ }
469
+
470
+ stopApHead() {
471
+ this.muteBtn.disabled = true;
472
+ this.messageBtn.disabled = true;
473
+ this.windModeBtn.disabled = true;
474
+ this.trackModeBtn.disabled = true;
475
+ this.autoBtn.disabled = true;
476
+ this.standbyBtn.disabled = true;
477
+ this.plus1Btn.disabled = true;
478
+ this.plus10Btn.disabled = true;
479
+ this.minus1Btn.disabled = true;
480
+ this.minus10Btn.disabled = true;
481
+ this.prtTackBtn.disabled = true;
482
+ this.stbTackBtn.disabled = true;
483
+
484
+ this.apScreen.errorIconVisibility = 'hidden';
485
+
486
+ this.isApConnected = false; // hide ap screen
487
+ this.stopAllSubscriptions();
488
+ this.config.autoStart = false; // save power on state to autostart or not
489
+ this.WidgetManagerService.updateWidgetConfig(this.widgetUUID, this.config);
490
+ }
491
+
492
+ SetKeyboardMode(apMode: string) {
493
+ switch (apMode) {
494
+ case "standby":
495
+ this.trackModeBtn.disabled = true;
496
+ this.autoBtn.disabled = false;
497
+ this.standbyBtn.disabled = false;
498
+
499
+ this.windModeBtn.disabled = false;
500
+ this.plus1Btn.disabled = true;
501
+ this.plus10Btn.disabled = true;
502
+ this.minus1Btn.disabled = true;
503
+ this.minus10Btn.disabled = true;
504
+ this.prtTackBtn.disabled = true;
505
+ this.stbTackBtn.disabled = true;
506
+ break;
507
+
508
+ case "auto":
509
+ this.trackModeBtn.disabled = false;
510
+ this.autoBtn.disabled = false;
511
+ this.standbyBtn.disabled = false;
512
+
513
+ this.windModeBtn.disabled = false;
514
+ this.plus1Btn.disabled = false;
515
+ this.plus10Btn.disabled = false;
516
+ this.minus1Btn.disabled = false;
517
+ this.minus10Btn.disabled = false;
518
+ this.prtTackBtn.disabled = true;
519
+ this.stbTackBtn.disabled = true;
520
+ break;
521
+
522
+ case "wind":
523
+ this.trackModeBtn.disabled = true;
524
+ this.autoBtn.disabled = false;
525
+ this.standbyBtn.disabled = false;
526
+
527
+ this.windModeBtn.disabled = false;
528
+ this.plus1Btn.disabled = false;
529
+ this.plus10Btn.disabled = false;
530
+ this.minus1Btn.disabled = false;
531
+ this.minus10Btn.disabled = false;
532
+ this.prtTackBtn.disabled = false;
533
+ this.stbTackBtn.disabled = false;
534
+ break;
535
+
536
+ case "route":
537
+ this.trackModeBtn.disabled = false;
538
+ this.autoBtn.disabled = false;
539
+ this.standbyBtn.disabled = false;
540
+
541
+ this.windModeBtn.disabled = true;
542
+ this.plus1Btn.disabled = true;
543
+ this.plus10Btn.disabled = true;
544
+ this.minus1Btn.disabled = true;
545
+ this.minus10Btn.disabled = true;
546
+ this.prtTackBtn.disabled = true;
547
+ this.stbTackBtn.disabled = true;
548
+ break;
549
+
550
+ default:
551
+ break;
552
+ }
553
+ }
554
+
555
+ buildAndSendCommand(cmd: string) {
556
+ let cmdAction = commands[cmd];
557
+ if (typeof cmdAction === 'undefined') {
558
+ alert('Unknown Autopilot command: ' + cmd);
559
+ return null;
560
+ }
561
+ if ((this.actionToBeConfirmed !== '') && (this.actionToBeConfirmed !== cmd)) {
562
+ this.clearConfirmCmd();
563
+ }
564
+ if (((cmd === 'tackToPort')||(cmd === 'tackToStarboard'))&&(this.actionToBeConfirmed === '')) {
565
+ this.confirmTack(cmd);
566
+ return null;
567
+ }
568
+ if ((cmd === 'route')&&(this.currentAPState === 'route')&&(this.actionToBeConfirmed === '')) {
569
+ this.confirmAdvanceWaypoint(cmd);
570
+ return null;
571
+ }
572
+ if (this.actionToBeConfirmed === cmd) {
573
+ this.clearConfirmCmd();
574
+ if ((cmd === 'tackToPort')||(cmd === 'tackToStarboard')) {
575
+ this.sendCommand(cmdAction);
576
+ }
577
+ if ((cmd === 'route')&&(this.currentAPState === 'route')) {
578
+ this.sendCommand(commands['advanceWaypoint']);
579
+ }
580
+ return null;
581
+ }
582
+ this.sendCommand(cmdAction);
583
+ }
584
+
585
+ confirmAdvanceWaypoint(cmd: string) {
586
+ let message: string = "Repeat key <b>[Next Wpt]</b><br>to confirm<br>Advance Waypoint";
587
+ this.startConfirmCmd(cmd, message);
588
+ }
589
+
590
+ confirmTack(cmd: string) {
591
+ let message = "Repeat same key<br>to confirm<br>tack to ";
592
+ if (cmd === "tackToPort") {
593
+ message += "port";
594
+ this.actionToBeConfirmed = cmd;
595
+ } else if (cmd === "tackToStarboard") {
596
+ message += "starboard";
597
+ this.actionToBeConfirmed = cmd;
598
+ } else {
599
+ this.actionToBeConfirmed = "";
600
+ return null;
601
+ }
602
+ this.startConfirmCmd(cmd, message);
603
+ }
604
+
605
+ sendCommand(cmdAction) {
606
+ let requestId = this.SignalkRequestsService.putRequest(cmdAction["path"], cmdAction["value"], this.widgetUUID);
607
+ this.apScreen.activityIconVisibility = "visible";
608
+ setTimeout(() => {this.apScreen.activityIconVisibility = 'hidden';}, timeoutBlink);
609
+
610
+ console.log("AP Action:\n" + JSON.stringify(cmdAction));
611
+ }
612
+
613
+ commandReceived(cmdResult: skRequest) {
614
+ this.apScreen.activityIconVisibility = "visible";
615
+ clearTimeout(this.handleReceiveTimeout);
616
+ this.handleReceiveTimeout = setTimeout(() => {this.apScreen.activityIconVisibility = 'hidden';}, timeoutBlink);
617
+
618
+ if (cmdResult.statusCode != 200){
619
+ this.displayApError(cmdResult);
620
+ } else {
621
+ console.log("AP Received: \n" + JSON.stringify(cmdResult));
622
+ }
623
+ }
624
+
625
+ startConfirmCmd(cmd: string, message: string) {
626
+ this.countDownValue = countDownDefault;
627
+ this.actionToBeConfirmed = cmd;
628
+
629
+ this.apScreen.msgStencilInnerHTML = "<p>" + message + "</p>";
630
+ this.apScreen.msgStencilVisibility = "visible";
631
+
632
+ this.updateCountDownCounter(message);
633
+
634
+ clearTimeout(this.handleConfirmActionTimeout);
635
+
636
+ this.handleConfirmActionTimeout = setTimeout(() => {
637
+ this.apScreen.msgStencilVisibility = "hidden";
638
+ this.apScreen.msgStencilInnerHTML = "";
639
+ this.actionToBeConfirmed = "";
640
+ }, 5000);
641
+ }
642
+
643
+ clearConfirmCmd() : boolean {
644
+ clearTimeout(this.handleConfirmActionTimeout);
645
+ clearTimeout(this.handleCountDownCounterTimeout);
646
+ this.countDownValue = -1;
647
+ this.apScreen.msgStencilVisibility = "hidden";
648
+ this.apScreen.msgStencilInnerHTML = "";
649
+ this.actionToBeConfirmed = '';
650
+ return null;
651
+ }
652
+
653
+ updateCountDownCounter(message: string) {
654
+ if (this.countDownValue > 0) {
655
+ clearTimeout(this.handleCountDownCounterTimeout);
656
+ this.apScreen.msgStencilInnerHTML = "<p>" + message + "</p>" + "<h1 class='counterText'>" + this.countDownValue.toString() + "</h1>";
657
+ this.countDownValue -= 1;
658
+ this.handleCountDownCounterTimeout = setTimeout(() => {
659
+ this.updateCountDownCounter(message);
660
+ }, 1000);
661
+ } else {
662
+ clearTimeout(this.handleCountDownCounterTimeout);
663
+ }
664
+ }
665
+
666
+ displayApError(cmdResult: skRequest) {
667
+ let errMsg = cmdResult.statusCode + " - " +cmdResult.statusCodeDescription;
668
+ if (cmdResult.message){
669
+ errMsg = errMsg + " Server Message: " + cmdResult.message;
670
+ }
671
+ this.apScreen.errorStencilInnerText = errMsg;
672
+ this.apScreen.errorStencilVisibility = "visible";
673
+
674
+ clearTimeout(this.handleDisplayErrorTimeout);
675
+
676
+ this.handleDisplayErrorTimeout = setTimeout(() => {
677
+ this.apScreen.errorStencilVisibility = "hidden";
678
+ this.apScreen.errorStencilInnerText = "";
679
+ }, 6000);
680
+ this.apScreen.errorIconVisibility = 'visible';
681
+ }
682
+
683
+ getNextNotification(skPath: string): string {
684
+ let notificationsKeys = Object.keys(this.notificationsArray);
685
+ let newSkPathToAck: string = "";
686
+ let index: number = 0;
687
+ if (notificationsKeys.length > 0) {
688
+ if (typeof skPath !== "undefined") {
689
+ index = notificationsKeys.indexOf(skPath) + 1;
690
+ } else {
691
+ index = 0;
692
+ }
693
+ if (notificationsKeys.length <= index) {
694
+ index = 0;
695
+ }
696
+ newSkPathToAck = notificationsKeys[index];
697
+ }
698
+ return newSkPathToAck;
699
+ }
700
+
701
+ setNotificationMessage(value) {
702
+ this.apScreen.activityIconVisibility = "visible";
703
+ clearTimeout(this.handleReceiveTimeout);
704
+ this.handleReceiveTimeout = setTimeout(() => {this.apScreen.activityIconVisibility = 'hidden';}, timeoutBlink);
705
+
706
+ if (typeof value.path !== 'undefined') {
707
+ value.path = value.path.replace('notifications.', '');
708
+ if (typeof value.value !== 'undefined') {
709
+ if (value.value.state === 'normal') {
710
+ if (this.apScreen.messageInnerText === this.notificationsArray[value.path]) {
711
+ this.apScreen.messageInnerText = '';
712
+ }
713
+ delete this.notificationsArray[value.path]
714
+ } else {
715
+ this.notificationsArray[value.path] = value.value.message.replace("Pilot", "");
716
+ this.apScreen.messageInnerText = this.notificationsArray[value.path];
717
+ }
718
+ }
719
+ }
720
+ this.alarmsCount = Object.keys(this.notificationsArray).length;
721
+ if (this.alarmsCount > 0) {
722
+ this.muteBtn.disabled = false;
723
+ if (this.apScreen.messageInnerText == "") {
724
+ this.apScreen.messageInnerText = Object.keys(this.notificationsArray)[0];
725
+ }
726
+ } else {
727
+ this.muteBtn.disabled = true;
728
+ this.alarmsCount = 0;
729
+ this.apScreen.messageInnerText = "";
730
+ }
731
+ }
732
+
733
+ notificationToValue(skPathToAck: string): string {
734
+ let message: string = this.notificationsArray[skPathToAck];
735
+ if (typeof message == "undefined") {
736
+ message = "No alarm present...";
737
+ }
738
+ return message;
739
+ }
740
+
741
+ notificationScroll() {
742
+ if ((Object.keys(this.notificationsArray).length > 0) && (this.skPathToAck == "")) {
743
+ this.skPathToAck = Object.keys(this.notificationsArray)[0];
744
+ }
745
+
746
+ this.skPathToAck = this.getNextNotification(this.skPathToAck);
747
+ // Not sure about this DIV ??? May be message area???
748
+ // silenceScreenTextDiv.innerHTML = notificationToValue(skPathToAck);
749
+ this.apScreen.messageInnerText = this.notificationToValue(this.skPathToAck);
750
+ this.apScreen.messageVisibility = 'visible';
751
+ clearTimeout(this.handleMessageTimeout);
752
+ this.handleMessageTimeout = setTimeout(() => {
753
+ this.apScreen.messageInnerText = "";
754
+ this.apScreen.messageVisibility = 'hidden';
755
+ }, 2000);
756
+ }
757
+
758
+ sendSilence() {
759
+ if (this.apScreen.messageVisibility != 'visible') {
760
+ this.apScreen.messageVisibility = 'visible';
761
+
762
+ if ((Object.keys(this.notificationsArray).length > 0) && (this.skPathToAck == "")) {
763
+ this.skPathToAck = Object.keys(this.notificationsArray)[0];
764
+ }
765
+ } else {
766
+ if (this.skPathToAck !== "") {
767
+ this.sendCommand({"path":"notifications." + this.skPathToAck + ".state","value":"normal"});
768
+ // this.sendCommand({"path":"notifications." + skPathToAck + ".method","value":[]});
769
+ }
770
+ this.apScreen.messageVisibility = 'hidden';
771
+ }
772
+ this.apScreen.messageInnerText = this.notificationToValue(this.skPathToAck);
773
+ }
774
+ }