mcu.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. var messageQueue = [];
  2. var bConfigUpdate = false;
  3. var dateCheck = new Date();
  4. var secCurrent = dateCheck.getSeconds();
  5. // helper functions
  6. /** Omega -> MCU**/
  7. // perform the sending to mcu
  8. function sendMcuCmd (cmd, payload) {
  9. print ('sendMcuCmd, cmd.length = ' + cmd.length + ' payload.length = ' + payload.length);
  10. if (cmd.length === 1 && payload.length >= 1) {
  11. var data = '~' + cmd + payload + ';';
  12. print('Sending command to mcu: ' + data);
  13. serialWrite(String(data));
  14. }
  15. }
  16. // --- functions to send commands to the mcu --- //
  17. function setMcuTime (payload) {
  18. var serialCmd = 'T';
  19. sendMcuCmd(serialCmd, String(payload));
  20. }
  21. function setMcuHourMode (payload) {
  22. var serialCmd = 'H';
  23. var serialPayload = parseInt(payload);
  24. if (serialPayload === 12 || serialPayload === 24 ) {
  25. sendMcuCmd(serialCmd, String(serialPayload));
  26. }
  27. }
  28. function setMcuNightLight (payload) {
  29. var serialCmd = 'L';
  30. sendMcuCmd(serialCmd, String(parseInt(payload)));
  31. }
  32. function setMcuButton (id, payload) {
  33. var serialCmd = 'b';
  34. if (typeof id !== 'undefined') {
  35. var serialPayload = String(id) + String(parseInt(payload));
  36. sendMcuCmd(serialCmd, String(serialPayload));
  37. }
  38. }
  39. function setMcuButtons (value) {
  40. var serialCmd = 'l';
  41. var serialPayload = String(value[0]) + ':' + String(value[1]) + ':' + String(value[2]) + ':' + String(value[3]);
  42. sendMcuCmd(serialCmd, String(serialPayload));
  43. }
  44. function setMcuTimeDisplayBrightness (payload) {
  45. var serialCmd = 'B';
  46. sendMcuCmd(serialCmd, String(parseInt(payload)));
  47. }
  48. function setMcuDayNightLed (payload) {
  49. var serialCmd = 'D';
  50. var serialPayload = ((payload === true || payload === 'true') ? 1 : 0);
  51. sendMcuCmd(serialCmd, String(serialPayload));
  52. }
  53. function setMcuInit () {
  54. var serialCmd = 'B';
  55. var serialPayload = '1';
  56. sendMcuCmd(serialCmd, String(serialPayload));
  57. }
  58. // parse mqtt messages
  59. function handleSetProperty (e) {
  60. if (typeof e.cmd !== 'undefined' && typeof e.value !== 'undefined') {
  61. // var serialCmd = '';
  62. // var serialPayload = '';
  63. switch (e.cmd) {
  64. case 'rtc':
  65. case 'time':
  66. setMcuTime (e.value);
  67. break;
  68. case 'hour mode':
  69. case 'hourMode':
  70. // serialPayload = parseInt(e.value);
  71. // if (serialPayload === 12 || serialPayload === 24 ) {
  72. // serialCmd = 'H';
  73. // }
  74. setMcuHourMode(e.value);
  75. break;
  76. case 'nightlight':
  77. // serialPayload = parseInt(e.value);
  78. // serialCmd = 'L';
  79. setMcuNightLight(e.value)
  80. break;
  81. case 'button':
  82. if (typeof e.id !== 'undefined') {
  83. // serialCmd = 'b';
  84. // serialPayload = String(e.id) + String(parseInt(e.value));
  85. setMcuButton(e.id, e.value)
  86. }
  87. break;
  88. case 'buttons':
  89. if (Array.isArray(e.value) && e.value.length === 4) {
  90. print('value IS TOTALLY an array of length 4') // debug
  91. // serialCmd = 'l';
  92. // serialPayload = String(e.value[0]) + ':' + String(e.value[1]) + ':' + String(e.value[2]) + ':' + String(e.value[3]);
  93. setMcuButtons(e.value);
  94. }
  95. // debug
  96. else {
  97. print('value is NOT an array of length 4')
  98. }
  99. break;
  100. case 'brightnessTime':
  101. case 'timeDisplay':
  102. // serialCmd = 'B';
  103. // serialPayload = parseInt(e.value);
  104. setMcuTimeDisplayBrightness(e.value);
  105. break;
  106. case 'day-night-indicator':
  107. case 'dayNightLed':
  108. // serialCmd = 'D';
  109. // serialPayload = ((e.value === true || e.value === 'true') ? 1 : 0);
  110. setMcuDayNightLed(e.value);
  111. break;
  112. case 'init':
  113. // serialCmd = 'I';
  114. // serialPayload = '1';
  115. setMcuInit();
  116. break;
  117. default:
  118. break;
  119. }
  120. // if (serialPayload === '') {
  121. // serialPayload = e.value;
  122. // }
  123. //
  124. // sendMcuCmd(serialCmd, String(serialPayload));
  125. // TODO: publish ack to set
  126. }
  127. }
  128. /** MCU -> Omega **/
  129. // decode received button messages
  130. function decodeButtons(inputStr) {
  131. var buttons = [];
  132. var payload = parseInt(inputStr.slice(0,2), 16);
  133. var duration = parseInt(inputStr.slice(2));
  134. print('button payload is ' + payload + ', pressed for ' + duration + ' milliseconds');
  135. // check which buttons have been pressed
  136. if (payload & 0x01) {
  137. buttons.push(0);
  138. }
  139. if (payload & 0x02) {
  140. buttons.push(1);
  141. }
  142. if (payload & 0x04) {
  143. buttons.push(2);
  144. }
  145. if (payload & 0x08) {
  146. buttons.push(3);
  147. }
  148. if (buttons.length > 0) {
  149. var obj = {
  150. id: buttons[0],
  151. action: 'press',
  152. duration: duration,
  153. multitouch: false
  154. }
  155. // adjustments for multi-touch case
  156. if (buttons.length > 1) {
  157. obj['id'] = payload;
  158. obj['multitouch'] = true;
  159. }
  160. print ('button: ' + JSON.stringify(obj));
  161. publish('/button', JSON.stringify(obj));
  162. }
  163. }
  164. // decode received gesture messages
  165. function decodeGesture(inputStr) {
  166. var direction = ''
  167. // publish to gesture topic
  168. switch (inputStr) {
  169. case 'L':
  170. direction = 'left';
  171. break;
  172. case 'R':
  173. direction = 'right';
  174. break;
  175. case 'U':
  176. direction = 'up';
  177. break;
  178. case 'D':
  179. direction = 'down';
  180. break;
  181. case 'X':
  182. default:
  183. direction = 'none';
  184. break;
  185. }
  186. publish('/gesture', JSON.stringify({
  187. direction: direction
  188. }))
  189. // implement card switching
  190. // TODO: this functionality should be moved to the card manager
  191. switch (inputStr) {
  192. // more natural input:
  193. // gesture left makes card animate leftward
  194. case 'L':
  195. direction = 'right';
  196. break;
  197. case 'R':
  198. direction = 'left';
  199. break;
  200. default:
  201. direction = '';
  202. break;
  203. }
  204. if (direction !== '') {
  205. var msg = {
  206. cmd: 'select_card',
  207. action: direction
  208. };
  209. print ('gesture: ' + direction)
  210. publish('/card', JSON.stringify(msg));
  211. }
  212. }
  213. // calculate battery percentage
  214. var batterySteps = [
  215. 3.65,
  216. 3.7,
  217. 3.78,
  218. 3.9,
  219. 4.15
  220. ];
  221. function calculateBatteryPercentage(a) {
  222. var detectedVoltage = a * 3.3 / 1024.0;
  223. var batteryVoltage = detectedVoltage * 1.49;
  224. for (var i = batterySteps.length; i >= 0; i--) {
  225. if (batteryVoltage >= batterySteps[i]) {
  226. return i;
  227. }
  228. }
  229. // default is empty
  230. return 0;
  231. }
  232. // decode battery voltage(
  233. function decodeBattery (input) {
  234. var payload = {
  235. cmd: 'update',
  236. elements: [{
  237. type: 'battery',
  238. value: calculateBatteryPercentage(input)
  239. }]
  240. };
  241. publish('/status', JSON.stringify(payload));
  242. }
  243. function wifiStatus (input) {
  244. var payload = {
  245. cmd: 'update',
  246. elements: [{
  247. type: 'wifi',
  248. value: input
  249. }]
  250. };
  251. publish('/status', JSON.stringify(payload));
  252. }
  253. // decode time from MCU
  254. function decodeTime (inputTime) {
  255. if (inputTime.match(/^\d+$/) !== null) {
  256. print('received date: ' + inputTime);
  257. updateSystemTime(inputTime);
  258. }
  259. }
  260. // parse property received from MCU
  261. function handleReceivedProperty(cmd, payload) {
  262. switch (cmd) {
  263. case 'V':
  264. // battery voltage (0-1023)
  265. decodeBattery(payload);
  266. break;
  267. case 'A':
  268. // ambient light (0-?)
  269. // TODO: implement this when supported by hw
  270. break;
  271. case 't':
  272. // touch button
  273. decodeButtons(payload);
  274. break;
  275. case 'G':
  276. // gesture
  277. decodeGesture(payload);
  278. break;
  279. case 'i':
  280. // time from RTC
  281. decodeTime(payload);
  282. break;
  283. default:
  284. print ('Unrecognized command');
  285. break;
  286. }
  287. }
  288. // parse string of received messages from MCU
  289. function handleReceivedProperties (msg) {
  290. var props = msg.split(/\r?\n/);
  291. props.forEach(function(element) {
  292. if (element) {
  293. var components = element.match(/^~(.)(.+);/);
  294. if (components != null && components.length === 3) {
  295. print ('cmd: ' + components[1] + ', value: ' + components[2]);
  296. handleReceivedProperty(components[1], components[2]);
  297. }
  298. }
  299. });
  300. }
  301. // config functions to read and implement config changes
  302. function readConfig() {
  303. readFile('/etc/config.json', '', function (err, data) {
  304. if (!err) {
  305. var config;
  306. try {
  307. state = JSON.parse(data);
  308. } catch(e) {
  309. print(e); // error in the above string!
  310. return null;
  311. }
  312. // apply the settings from the config file
  313. if (state.config.hourMode) setMcuHourMode(state.config.hourMode);
  314. if (typeof(state.config.dayNightLed) == typeof(true)) setMcuDayNightLed(state.config.dayNightLed);
  315. if (state.config.brightnessTime) setMcuTimeDisplayBrightness(state.config.brightnessTime);
  316. }
  317. print('configuration: hourMode = ' + state.config.hourMode + '; dayNightLed = ' + state.config.dayNightLed + '; brightnessTime = ' + state.config.brightnessTime);
  318. });
  319. }
  320. function readWifiHelper(){
  321. var status;
  322. readFile('/tmp/wifi-active', '', function (err, data) {
  323. if (!err) {
  324. try {
  325. status = data;
  326. } catch(e) {
  327. print(e); // error in the above string!
  328. return null;
  329. }
  330. }
  331. print('status ' + status);
  332. });
  333. if(status.includes("1")){
  334. wifiStatus(1);
  335. } else {
  336. wifiStatus(0);
  337. }
  338. }
  339. // base functions
  340. function setup() {
  341. connect('localhost', 1883, null, function () {
  342. print('subscribing to topic');
  343. subscribe('/set');
  344. subscribe('/config/update');
  345. print('opening serial port');
  346. openSerialPort("/dev/ttyS1");
  347. sendMcuCmd ("I", "0");
  348. });
  349. sleep(2);
  350. }
  351. function loop() {
  352. // handle any config updates
  353. if (bConfigUpdate) {
  354. readConfig()
  355. bConfigUpdate = false;
  356. }
  357. // handle any incoming mqtt messages
  358. if (messageQueue.length > 0) {
  359. for (var i = 0; i < messageQueue.length; i++) {
  360. handleSetProperty(messageQueue[i]);
  361. }
  362. messageQueue = [];
  363. }
  364. // look for new messages from mcu -- this is a blocking call
  365. var msg = serialRead();
  366. if (msg !== null && msg.length > 0) {
  367. print("received serial message of length " + msg.length + " value is " + msg);
  368. handleReceivedProperties(msg);
  369. }
  370. dateLocal = new Date();
  371. if((dateLocal.getSeconds() % 15) == 0 && secCurrent != dateLocal.getSeconds()){
  372. print("update wifi status");
  373. secCurrent = dateLocal.getSeconds();
  374. readWifiHelper();
  375. // check if connected
  376. // send status message
  377. }
  378. }
  379. function onMessage(e) {
  380. if (typeof e.topic !== 'undefined' && typeof e.payload !== 'undefined' ) {
  381. print('message! topic: ' + e.topic + ', value: ' + JSON.stringify(e.payload));
  382. if (e.topic === '/set') {
  383. messageQueue.push(e.payload);
  384. } else if (e.topic === '/config/update') {
  385. bConfigUpdate = true;
  386. }
  387. }
  388. }