From ca65ff6be6591b90798f2df510c5cad27f88b44e Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 17:50:07 +0100 Subject: [PATCH 01/72] Create app.js --- apps/BLEcontroller/app.js | 424 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 apps/BLEcontroller/app.js diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js new file mode 100644 index 000000000..a486917cf --- /dev/null +++ b/apps/BLEcontroller/app.js @@ -0,0 +1,424 @@ +/* + +========================================================== + +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. + +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE + +Written by Richard Hopkins, May 2020 + +========================================================== + +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +/* + +CONFIGURATION AREA - STATE VARIABLES + +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_mic = {value: true}; +var status_spk = {value: true}; + +/* trsnsmit message */ +const transmit = (state,object,status) => { + message = { + state: state, + obj: object, + val: status, + }; + print(message); + return JSON.stringify(message); +}; + +/* + +CONFIGURATION AREA - ICON DEFINITIONS + +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs + +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object + +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "mic_off", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Wf47/HJZLjHZ45RHrI7NHJYhLHqoZJA54hNHr5lTXL6vPSra5jKbo9REZrLRHa5DTXp47jAA7TTF7INLRqY7fdKavhXKo5te6wA==" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + } +]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* + +CONFIGURATION AREA - BUTTON DEFINITIONS + +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button + +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. + +*/ +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +var micBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'mic_off', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'mic_on', + value: status_mic + }; + +var spkBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'spk_off', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'spk_on', + value: status_spk + }; + +/* + +CONFIGURATION AREA - SCREEN DEFINITIONS + +a screen can have a button (as defined above) +on the left and/or the right of the screen. + +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. + +*/ +const menuScreen = { + left: autoBtn, + right: joystickBtn, + btn1: "comms" +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const commsScreen = { + left: micBtn, + right: spkBtn, + btn3: "back" +}; + +/* base state definition + +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states + +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* + +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS + +This area defines how each screen behaves. + +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. + +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). + +The screens are defined above. + +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. + +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. + +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. + +To add in additional capabilities for button presses, simply add +an additional 'if' statement. + +For toggle buttons, the value of the sppropiate status object is +inversed and the new value transmitted. + +*/ + +/* The Home State/Page is where the application beings */ +const Home = new State({ + state: "Home", + screen: menuScreen, + events: (event) => { + if ((event.object == "right") && (event.status == "end")) { + transmit("Joystick", "joystick", "on"); + return Joystick; + } + if ((event.object == "top") && (event.status == "end")) { + return Comms; + } + if ((event.object == "left") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "auto", onOff(status_auto.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Comms page state */ +const Comms = new State({ + state: "Comms", + screen: commsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "left") && (event.status == "end")) { + status_mic.value = !status_mic.value; + transmit(this.state, "mic", onOff(status_mic.value)); + return this; + } + if ((event.object == "right") && (event.status == "end")) { + status_spk.value = !status_spk.value; + transmit(this.state, "spk", onOff(status_spk.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released + +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. + +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. + +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. + +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "mdiddle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,24,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen From 033b227e674a50e55a1bdc356bedc90045c18dd9 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 17:56:05 +0100 Subject: [PATCH 02/72] Create app-icon.js --- apps/BLEcontroller/app-icon.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/BLEcontroller/app-icon.js diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js new file mode 100644 index 000000000..da959f36a --- /dev/null +++ b/apps/BLEcontroller/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("nk8wkBiIA/AH4A/AA8QaIYdYd4gOLG5odMBhYcHCBAuEgJVVDqQLHCA0BNpA6QSYgd5LLYaFSq4dQLR4wJLyQdKQJBbOJZwdYBxypRS6AdZJZ4drPH54/PH541DjIdCDjRaBDjYAhTITUeDy4cEDzAdXCwoANGh4ANIRASKFBQdRBZodtLLq0TDv4dZAH4A/AH4ArA==")) From 0e67901c39932c90cf93d9529f50d13f959a7042 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 17:59:52 +0100 Subject: [PATCH 03/72] Update app-icon.js --- apps/BLEcontroller/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js index da959f36a..db64a917d 100644 --- a/apps/BLEcontroller/app-icon.js +++ b/apps/BLEcontroller/app-icon.js @@ -1 +1 @@ -require("heatshrink").decompress(atob("nk8wkBiIA/AH4A/AA8QaIYdYd4gOLG5odMBhYcHCBAuEgJVVDqQLHCA0BNpA6QSYgd5LLYaFSq4dQLR4wJLyQdKQJBbOJZwdYBxypRS6AdZJZ4drPH54/PH541DjIdCDjRaBDjYAhTITUeDy4cEDzAdXCwoANGh4ANIRASKFBQdRBZodtLLq0TDv4dZAH4A/AH4ArA==")) +E.toArrayBuffer(atob("PDyEARERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREQAAAAAAEREREREREREREQAAEREREREREREREAAAAAAAAAAAERERERERERERAAAAABERERERERERAAAAAAAAAAAAEREREREREREQAAAAAAERERERERERAAAAAAAREREREREREREREREQAAAAAAERERERERERAAAAAAEREREREREREREREREAAAEQAAAAAAAAAAAAAAAAABEREREREREREREREREAABERAAAAAAAAAAAAAAAAABEREREREREREREREREAABERAAAAAAAAAAAAAAAAABEREREREREREREREREAAAEQAAAAAAAAAAAAAAAAABEREREREREREREREREQAAAAAAARERERERERAAAAAAEREREREREREREREREQAAAAAAARERERERERAAAAAAARERERERERERERERERAAAAAAABERERERERAAAAAAAAAAAAEREREREREREREQAAAAABEREREREREAAAAAAAAAAAERERERERERERERAAAAAAEREREREREREREQAAAAAAERERERERERERERAAAAAAERERERERERERERAAAAAAEREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREQAAAAABEREREREREREREREREREREREREREREREREQAAAAABERERERERERERERERERERERERERERERERERAAAAAAERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREQAAAAABEREREREREREREREREREREREREREREREREQAAAAABERERERERERERERERERERERERERERERERERAAAAAAERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREREAAAAREREREREREREREREREREREREREREREREREREAABEREREREREREREREREREREREREREREREREREREQEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQAAABERERERERERERERERERERERERERERERERERAAAAAAAREREREREREREREREREREREREREREREREAAAAAAAAAEREREREREREREREREREREREREREREREAAAAAAAAAERERERERERERERERERERERAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREREREQAAAAAAAAAAAAAAAAAAAAAAAAAAABEREREREREREAAAAAAAAAAAAAARAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAEREAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAEREAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAARAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQ==")) From ed20c802da0f7b577754d37c4e439be01cc54290 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:01:52 +0100 Subject: [PATCH 04/72] Add files via upload --- apps/BLEcontroller/BLEcontroller.png | Bin 0 -> 579 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/BLEcontroller/BLEcontroller.png diff --git a/apps/BLEcontroller/BLEcontroller.png b/apps/BLEcontroller/BLEcontroller.png new file mode 100644 index 0000000000000000000000000000000000000000..df529e982df191f6cd16e13b91503880546e3b05 GIT binary patch literal 579 zcmV-J0=)f+P)0&l=6uncr60#<-4LD4u}oUzxLt0>JPsZnf=H(GxN=RY=~QshW#_o)vQwR6Y53F~sJV_j|%*5y{mx(s~cZ7WuRX_Eh7pF8SZ{s6XtF}HHkrwH5v6Rw41 zNv~@GuIa$r4sHRLz>^=B{%f=THUEMs;D+eweGN>yk*LQe-jt3q8=UAHE`(~Zj@)Qt ztU1v8g9121lQz+evKsB_gZkjyq`k;P$V1t$Rs%<)Kikb8MP#4*f0#kFbpFtz5!vGy!T@R R(GCCr002ovPDHLkV1mbo0=NJG literal 0 HcmV?d00001 From 89a49189f4c4694a971e332b69a0a62a569e6900 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:07:04 +0100 Subject: [PATCH 05/72] Update apps.json --- apps.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps.json b/apps.json index 04c2f637d..6385082f6 100644 --- a/apps.json +++ b/apps.json @@ -1760,5 +1760,20 @@ { "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true } ], "version": "0.03" + }, +{ + "id": "BLEcontroller", + "name": "BLE Robot Controller with Joystick", + "shortName": "BLE Controller", + "icon": "BLEcontroller.png", + "version": "0.01", + "description": "A configurable controller for BLE robots, including a basic joystick.", + "tags": "tools", + "readme": "README.md", + "allow_emulator":true, + "storage": [ + { "name": "BLEcontroller.app.js", "url": "app.js" }, + { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } + ] } ] From 6bf2b7d9691d224b8fdf33b557a378fa6f06e9fd Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:09:54 +0100 Subject: [PATCH 06/72] Create README.md --- apps/BLEcontroller/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 apps/BLEcontroller/README.md diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md new file mode 100644 index 000000000..172bb1758 --- /dev/null +++ b/apps/BLEcontroller/README.md @@ -0,0 +1,3 @@ +=== BLE Controller +==Some text += More text From 0d013efb8e1c342a187c54027a75f88fe2acbcd2 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:13:23 +0100 Subject: [PATCH 07/72] Update app-icon.js --- apps/BLEcontroller/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js index db64a917d..0f5e1aff6 100644 --- a/apps/BLEcontroller/app-icon.js +++ b/apps/BLEcontroller/app-icon.js @@ -1 +1 @@ -E.toArrayBuffer(atob("PDyEARERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREQAAAAAAEREREREREREREQAAEREREREREREREAAAAAAAAAAAERERERERERERAAAAABERERERERERAAAAAAAAAAAAEREREREREREQAAAAAAERERERERERAAAAAAAREREREREREREREREQAAAAAAERERERERERAAAAAAEREREREREREREREREAAAEQAAAAAAAAAAAAAAAAABEREREREREREREREREAABERAAAAAAAAAAAAAAAAABEREREREREREREREREAABERAAAAAAAAAAAAAAAAABEREREREREREREREREAAAEQAAAAAAAAAAAAAAAAABEREREREREREREREREQAAAAAAARERERERERAAAAAAEREREREREREREREREQAAAAAAARERERERERAAAAAAARERERERERERERERERAAAAAAABERERERERAAAAAAAAAAAAEREREREREREREQAAAAABEREREREREAAAAAAAAAAAERERERERERERERAAAAAAEREREREREREREQAAAAAAERERERERERERERAAAAAAERERERERERERERAAAAAAEREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREQAAAAABEREREREREREREREREREREREREREREREREQAAAAABERERERERERERERERERERERERERERERERERAAAAAAERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREAAAAAAREREREREREREREREREREREREREREREREREQAAAAABEREREREREREREREREREREREREREREREREQAAAAABERERERERERERERERERERERERERERERERERAAAAAAERERERERERERERERERERERERERERERERERAAAAAAEREREREREREREREREREREREREREREREREREAAAAREREREREREREREREREREREREREREREREREREAABEREREREREREREREREREREREREREREREREREREQEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQAAABERERERERERERERERERERERERERERERERERAAAAAAAREREREREREREREREREREREREREREREREAAAAAAAAAEREREREREREREREREREREREREREREREAAAAAAAAAERERERERERERERERERERERAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREREREQAAAAAAAAAAAAAAAAAAAAAAAAAAABEREREREREREAAAAAAAAAAAAAARAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAEREAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAEREAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAARAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREQ==")) +E.toArrayBuffer(atob("QECEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEREREhEhEREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREj////MzIREREAAAAAAAAAAAAAAAAAAAAAAAAAARERP//////zMzIRERAAAAAAAAAAAAAAAAAAAAAAAAARES/////////zMzIREQAAAAAAAAAAAAAAAAAAAAAAARET//////////8zMzEREAAAAAAAAAAAAAAAAAAAAAARET////////////MzMxERAAAAAAAAAAAAAAAAAAAAABET/////////////zMzMREAAAAAAAAAAAAAAAAAAAABES//////////////8zMyERAAAAAAAAAAAAAAAAAAABES///////////////zMzMREQAAAAAAAAAAAAAAAAAAERP//////zMzMzP///8zMzERAAAAAAAAAAAAAAAAAAARL//////zMzMzMz///zMzMhEAAAAAAAAAAAAAAAAAARE//////zM///MzM///8zMyERAAAAAAAAAAAAAAAAABEf/////zM///8zMzP//zMzMREAAAAAAAAAAAAAAAAAES//////M////zMzM///MzMxEQAAAAAAAAAAAAAAAAARL/////8z//MzMzMz///zMzIRAAAAAAAAAAAAAAAAARE//////zP/8zMzMzP///MzMhEQAAAAAAAAAAAAAAABET//////M//zMzMzM///8zMyERAAAAAAAAAAAAAAAAERP/////8zPzMzMzMz///zMzMREAAAAAAAAAAAAAAAARE//////zMzMzMzMzP///MzMxEQAAAAAAAAAAAAAAABET//////MzMzMzMzM///8zMzERAAAAAAAAAAAAAAAAERP//////zMzMzMzM////zMzMREAAAAAAAAAAAAAAAARE///////8zMzMzM/////MzMxEQAAAAAAAAAAAAAAABET////////MzMzM/////8zMyERAAAAAAAAAAAAAAABERE/////////8z///////zMyEREQAAAAAAAAAAAAAAERERP/////////////////MzERERAAAAAAAAAAAAAAERIhEv////////////////8zIRIhEQAAAAAAAAAAAAARH/ER/////////////////zMRH/ERAAAAAAAAAAAAABESIRL/////////////////MyESIREAAAAAAAAAAAAAERERE/////////////////8zMREREQAAAAAAAAAAAAAREREv/////////////////zMyERERAAAAAAAAAAAAARERE///////////////////MzMhEREQAAAAAAAAAAARERET//////////////////8zMzEREREAAAAAAAAAABEQERP//////////////////zMzMREBEQAAAAAAAAABERARE///////////////////MzMxEQEREAAAAAAAABERABET//////////////////8zMzERABERAAAAAAERERAAERP//////////////////zMzMREAAREREAAAEREREAARE///////////////////MzMxEQABERERAAEREREQABET//////////////////8zMzERAAEREREQAREzERAAERP//////////////////zMzMREAAREAERABEf8REAARE///////////////////MzMxEQABEQAREAEREREQABET//////////////////8zMzERAAEREREQABEREQAAERP/8///P/8z//P/8z//PzMzMREAABEREQAAARERAAARE//zP/M//zP/Mz/zP/MzMzMxEQAAEREQAAAAAREAABET//P//z//M//z//M//z8zMzERAAAREAAAAAABEQAAERP//////////////////zMzMREAABEQAAAAAAEREAAREv//////////////////MzMhEQABERAAAAAAABEQAAEREREREREREREREREREREREREQAAERAAAAAAAAEREAABEREREREREREREREREREREREQAAEREAAAAAAAARERAAAREREREREREREREREREREREQAAEREQAAAAAAAREREQAAAAAAAAEREREREREREQAAAAAAEREREAAAAAAREREREAAAAAAAAREREREREREREAAAAAERERERAAAAABEQABEQAAAAAAABERERERERERERAAAAAREAAREAAAAAEQAAERAAAAAREREREREREREREREAAAABEAABEQAAAAARAAABEAAAARERERERERERERERERAAAAEQAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) From 0bb93839e65d107a5a56d105199ac80a55740e64 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:14:17 +0100 Subject: [PATCH 08/72] Add files via upload --- apps/BLEcontroller/BLEcontroller.png | Bin 579 -> 3473 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/BLEcontroller/BLEcontroller.png b/apps/BLEcontroller/BLEcontroller.png index df529e982df191f6cd16e13b91503880546e3b05..e42fe5dae5a7bc3cfc4aa20380f5a036df9d081f 100644 GIT binary patch literal 3473 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 delta 572 zcmV-C0>k~08^Z)4iBL{Q4GJ0x0000DNk~Le0000y0000y2nGNE06P5Ha*-hve*ySO zL_t(&f$f?-OT%yw#(%zppx`Ll!AZYDK}5ktT@@$6$+4>-4uYRW2PwEnt>EqpBH}1I zh^~rOaS>mJq!5cu&g7DRD))n1+Hm(gy?>6TS1=62FboYAfOp_4BK`$Zv#N%BfD&*F zyaI2)DXkX?r}JJNp{T89bhe@1S;c+}|v zR)8x((Kub6LC3T@MM2THU2eua4jvwYNT&0+a!sk}RB+K{=eX#yQ>@EP!n)k*SeJhZ z>vF4OU2YQAA>3# zZUL9TlOLDyk*LQe-jt3q8=UAHE`(~Zj@)QttU1v8g9121lQz+ zevKsB_gZkjyq`k;P$V1t$Rs%<)Kikb8MP#4*f0#kFbpFtz5!vG61?|g1JMou0000< KMNUMnLSTYaZ~#sK From 673e1c3c7bb326b62c9f352713deb63259f43d11 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:18:08 +0100 Subject: [PATCH 09/72] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 6385082f6..afac26dba 100644 --- a/apps.json +++ b/apps.json @@ -1767,7 +1767,7 @@ "shortName": "BLE Controller", "icon": "BLEcontroller.png", "version": "0.01", - "description": "A configurable controller for BLE robots, including a basic joystick.", + "description": "A configurable controller for BLE robots, with a basic four direction joystick.", "tags": "tools", "readme": "README.md", "allow_emulator":true, From 077728de67e620ef4dc9f71c4e62642759406429 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:18:56 +0100 Subject: [PATCH 10/72] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index afac26dba..c3780cfeb 100644 --- a/apps.json +++ b/apps.json @@ -1768,7 +1768,7 @@ "icon": "BLEcontroller.png", "version": "0.01", "description": "A configurable controller for BLE robots, with a basic four direction joystick.", - "tags": "tools", + "tags": "tool,bluetooth", "readme": "README.md", "allow_emulator":true, "storage": [ From ba68904acf2e6a436794d40e4236d28d697c1dea Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:23:51 +0100 Subject: [PATCH 11/72] Update app-icon.js --- apps/BLEcontroller/app-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app-icon.js b/apps/BLEcontroller/app-icon.js index 0f5e1aff6..662f43c5c 100644 --- a/apps/BLEcontroller/app-icon.js +++ b/apps/BLEcontroller/app-icon.js @@ -1 +1 @@ -E.toArrayBuffer(atob("QECEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEREREREREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABEREREhEhEREREAAAAAAAAAAAAAAAAAAAAAAAAAAAAREREj////MzIREREAAAAAAAAAAAAAAAAAAAAAAAAAARERP//////zMzIRERAAAAAAAAAAAAAAAAAAAAAAAAARES/////////zMzIREQAAAAAAAAAAAAAAAAAAAAAAARET//////////8zMzEREAAAAAAAAAAAAAAAAAAAAAARET////////////MzMxERAAAAAAAAAAAAAAAAAAAAABET/////////////zMzMREAAAAAAAAAAAAAAAAAAAABES//////////////8zMyERAAAAAAAAAAAAAAAAAAABES///////////////zMzMREQAAAAAAAAAAAAAAAAAAERP//////zMzMzP///8zMzERAAAAAAAAAAAAAAAAAAARL//////zMzMzMz///zMzMhEAAAAAAAAAAAAAAAAAARE//////zM///MzM///8zMyERAAAAAAAAAAAAAAAAABEf/////zM///8zMzP//zMzMREAAAAAAAAAAAAAAAAAES//////M////zMzM///MzMxEQAAAAAAAAAAAAAAAAARL/////8z//MzMzMz///zMzIRAAAAAAAAAAAAAAAAARE//////zP/8zMzMzP///MzMhEQAAAAAAAAAAAAAAABET//////M//zMzMzM///8zMyERAAAAAAAAAAAAAAAAERP/////8zPzMzMzMz///zMzMREAAAAAAAAAAAAAAAARE//////zMzMzMzMzP///MzMxEQAAAAAAAAAAAAAAABET//////MzMzMzMzM///8zMzERAAAAAAAAAAAAAAAAERP//////zMzMzMzM////zMzMREAAAAAAAAAAAAAAAARE///////8zMzMzM/////MzMxEQAAAAAAAAAAAAAAABET////////MzMzM/////8zMyERAAAAAAAAAAAAAAABERE/////////8z///////zMyEREQAAAAAAAAAAAAAAERERP/////////////////MzERERAAAAAAAAAAAAAAERIhEv////////////////8zIRIhEQAAAAAAAAAAAAARH/ER/////////////////zMRH/ERAAAAAAAAAAAAABESIRL/////////////////MyESIREAAAAAAAAAAAAAERERE/////////////////8zMREREQAAAAAAAAAAAAAREREv/////////////////zMyERERAAAAAAAAAAAAARERE///////////////////MzMhEREQAAAAAAAAAAARERET//////////////////8zMzEREREAAAAAAAAAABEQERP//////////////////zMzMREBEQAAAAAAAAABERARE///////////////////MzMxEQEREAAAAAAAABERABET//////////////////8zMzERABERAAAAAAERERAAERP//////////////////zMzMREAAREREAAAEREREAARE///////////////////MzMxEQABERERAAEREREQABET//////////////////8zMzERAAEREREQAREzERAAERP//////////////////zMzMREAAREAERABEf8REAARE///////////////////MzMxEQABEQAREAEREREQABET//////////////////8zMzERAAEREREQABEREQAAERP/8///P/8z//P/8z//PzMzMREAABEREQAAARERAAARE//zP/M//zP/Mz/zP/MzMzMxEQAAEREQAAAAAREAABET//P//z//M//z//M//z8zMzERAAAREAAAAAABEQAAERP//////////////////zMzMREAABEQAAAAAAEREAAREv//////////////////MzMhEQABERAAAAAAABEQAAEREREREREREREREREREREREREQAAERAAAAAAAAEREAABEREREREREREREREREREREREQAAEREAAAAAAAARERAAAREREREREREREREREREREREQAAEREQAAAAAAAREREQAAAAAAAAEREREREREREQAAAAAAEREREAAAAAAREREREAAAAAAAAREREREREREREAAAAAERERERAAAAABEQABEQAAAAAAABERERERERERERAAAAAREAAREAAAAAEQAAERAAAAAREREREREREREREREAAAABEAABEQAAAAARAAABEAAAARERERERERERERERERAAAAEQAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) +E.toArrayBuffer(atob("MDCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAAAAAAAABERIQAAAAAAAAAAAAAAAAAAAAAAAAABERIRpiEQAAAAAAAAAAAAAAAAAAAAAAEREhOiImEqYAAAAAAAAAAAAAAAAAAAABESP///8zOFEQAAAAAAAAAAAAAAAAAAARI//////z8zp6AAAAAAAAAAAAAAAAAAES////////PzOFEAAAAAAAAAAAAAAAABEv////////8/MyGgAAAAAAAAAAAAAAARI//////////z8zIRAAAAAAAAAAAAAAARP/////8/P///M/IRAAAAAAAAAAAAAAES/////zgzM///M/OFEAAAAAAAAAAAAAET////84/zMzP/8z8hEAAAAAAAAAAAAAEf////M///gzP/8/MyEAAAAAAAAAAAABEv///zP/8zjzM/8/M4UQAAAAAAAAAAABEv///zP/M48zj//zPyEQAAAAAAAAAAABE////zP/ODMzj//zPyEQAAAAAAAAAAABE////zMzjyM48//zPyEQAAAAAAAAAAABE/////ODMzOPP/8/M4QQAAAAAAAAAAABE/////MzjzOD///zPyEQAAAAAAAAAAABE/////8zOPMz///zMzEQAAAAAAAAAAABEj//////PzP///8/MxhQAAAAAAAAAAARES////////////8/MRpyAAAAAAAAAAASMRP////////////zMRMhAAAAAAAAAAARMR////////////8/IRMhAAAAAAAAAAARES/////////////zMhp6AAAAAAAAAAEREv////////////8/MyEacAAAAAAAABERIv/////////////zPyERGAAAAAAAABEBE//////////////zPyEQEQAAAAAAAREBE//////////////zPyEQERAAAAABERABE//////////////zPyEQAREQAAEREgABE//////////////zPyEQABERIAESESABE//////////////zPyEQARESEAEfIRABE//////////////zPyEQAREBEAEREgABE//////z//////8/MzEQABERIAAREQABE/8/8z/zPz/z8/M/MzGAABERAAABEQABE/8/8/8/Pz/z8/PzPyEQABEQAAAAEQABE//////////////zPyEQABEAAAAAERAAETMzMzMzMjMzMzODIxEAAREAAAAAARAAEREhGmIRGhESaiYRKmEAARAAAAAAEREgABERIaYhEaERJqEmEQABERIAAAABERIaAAAAAAEREhGmIREAAAARESGgAAABEAARAAAAAAEREhGmIRGgAAARAAEQAAABEAARAAABERIRpiERoREgAAARAAEQAAAAAAAAAAABERIRpiERoREgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) From dfc54d8d73703eb816ed2c37817c0a61a09e9edf Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:24:17 +0100 Subject: [PATCH 12/72] Add files via upload --- apps/BLEcontroller/BLEcontroller.png | Bin 3473 -> 2642 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/apps/BLEcontroller/BLEcontroller.png b/apps/BLEcontroller/BLEcontroller.png index e42fe5dae5a7bc3cfc4aa20380f5a036df9d081f..3fa8575f30c5b25c3b1b21708de7281fed85de1c 100644 GIT binary patch literal 2642 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 A$p8QV literal 3473 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 From 0d8501f2d64e221ff80512cb819cdf4123c05141 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:26:13 +0100 Subject: [PATCH 13/72] Update apps.json --- apps.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps.json b/apps.json index c3780cfeb..ef6f68d11 100644 --- a/apps.json +++ b/apps.json @@ -1767,7 +1767,7 @@ "shortName": "BLE Controller", "icon": "BLEcontroller.png", "version": "0.01", - "description": "A configurable controller for BLE robots, with a basic four direction joystick.", + "description": "A configurable controller for BLE robots, with a basic four direction joystick. Easy to customise and add your own menus.", "tags": "tool,bluetooth", "readme": "README.md", "allow_emulator":true, From a38371d8d4e208552470718cf082c78e6e40f5df Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:36:54 +0100 Subject: [PATCH 14/72] Update README.md --- apps/BLEcontroller/README.md | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 172bb1758..a21db6240 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,3 +1,31 @@ -=== BLE Controller -==Some text -= More text +# BLE Robot Controller with Joystic + +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. Amaze your friends by controlling your robot from your watch! + +Commands are sent from the Controller to the BLE robot in a JSON format. + +## Usage + +The application can be configured at will by chaning the definitions of the screens, events, icons and buttons. + +Most changes are possible via data, rather than code change. + +## Features + +In its default state, it has three screens that provide the ability to: +turn the robot on or off +turn on and off its voice and microphone +make the robot move by spinning left or right and moving forward and backwards + +## Controls + +The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. + +## Requests + +In the first instance, please consult my blog post on this application here. + +## Creator + +Richard Hopkins, FIET CEng +May 2020 From ce066c2a3852895a293df19fdaa3a2ca13bff37a Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Sun, 17 May 2020 18:37:10 +0100 Subject: [PATCH 15/72] Update README.md --- apps/BLEcontroller/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index a21db6240..049a5f824 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,4 +1,4 @@ -# BLE Robot Controller with Joystic +# BLE Robot Controller with Joystick A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. Amaze your friends by controlling your robot from your watch! From 5df11d3c3d376902d01e782b883e0db7d1e094f7 Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Fri, 22 May 2020 22:09:52 +0100 Subject: [PATCH 16/72] Working transmission --- .vscode/launch.json | 17 ++++++++++ apps/BLEcontroller/app.js | 68 +++++++++++++-------------------------- 2 files changed, 39 insertions(+), 46 deletions(-) create mode 100644 .vscode/launch.json diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..771354e66 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "skipFiles": [ + "/**" + ], + "program": "${workspaceFolder}/http-server" + } + ] +} \ No newline at end of file diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index a486917cf..3afae6b4b 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -1,21 +1,15 @@ /* - ========================================================== - Simple event based robot controller that enables robot to switch into automatic or manual control modes. Behaviours are controlled via a simple finite state machine. - In automatic mode the robot will look after itself. In manual mode, the watch will provide simple forward, back, left and right commands. The messages will be transmitted to a partner BLE Espruino using BLE - Written by Richard Hopkins, May 2020 - ========================================================== - declare global variables for watch button statuses */ top_btn = false; middle_btn = false; @@ -23,10 +17,10 @@ left_btn= false; // the left side of the touch screen right_btn = false; // the right side of the touch screen bottom_btn = false; +msgNum = 0; // message number + /* - CONFIGURATION AREA - STATE VARIABLES - declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ @@ -35,24 +29,32 @@ var status_auto = {value: false}; var status_mic = {value: true}; var status_spk = {value: true}; -/* trsnsmit message */ +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + const transmit = (state,object,status) => { - message = { - state: state, - obj: object, - val: status, + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0.4), }; - print(message); - return JSON.stringify(message); + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); }; /* - CONFIGURATION AREA - ICON DEFINITIONS - Retrieve 30px PNG icons from: https://icons8.com/icon/set/speak/ios-glyphs - Create icons using: https://www.espruino.com/Image+Converter Use compression: true @@ -60,7 +62,6 @@ Transparency: true Diffusion: flat Colours: 16bit RGB Ouput as: Image Object - Add an additional element to the icons array with a unique name and the data from the Image Object */ @@ -133,20 +134,16 @@ const drawIcon = (name) => { }; /* - CONFIGURATION AREA - BUTTON DEFINITIONS - for a simple button, just define a primary colour and an icon name from the icon array and the text to display beneath the button - for toggle buttons, additionally provide secondary colours, icon name and text. Also provide a reference to a global variable for the value of the button. The global variable should be declared at the start of the program and it may be adviable to use the 'status_name' format to ensure it is clear. - */ var joystickBtn = { primary_colour: 0x653E, @@ -200,18 +197,14 @@ var spkBtn = { }; /* - CONFIGURATION AREA - SCREEN DEFINITIONS - a screen can have a button (as defined above) on the left and/or the right of the screen. - in adddition a screen can optionally have an icon for each of the three buttons on the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. - */ const menuScreen = { left: autoBtn, @@ -234,11 +227,9 @@ const commsScreen = { }; /* base state definition - Each of the screens correspond to a state; this class provides a constuctor for each of the states - */ class State { constructor(params) { @@ -249,39 +240,28 @@ class State { } /* - CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS - This area defines how each screen behaves. - Each screen corresponds to a different State of the state machine. This makes it much easier to isolate behaviours between screens. - The state value is transmitted whenever a button is pressed to provide context (so the receiving device, knows which button was pressed on which screen). - The screens are defined above. - The events section identifies if a particular button has been pressed and released on the screen and an action can then be taken. - The events function receives a notification from a mySetWatch which provides an event object that identifies which button and whether it has been pressed down or released. Actions can then be taken. The events function will always return a State object. - If the events function returns different State from the current one, then the state machine will change to that new State and redrsw the screen appropriately. - To add in additional capabilities for button presses, simply add an additional 'if' statement. - For toggle buttons, the value of the sppropiate status object is inversed and the new value transmitted. - */ /* The Home State/Page is where the application beings */ @@ -352,19 +332,15 @@ const onOff= status => status ? "on" : "off"; /* create watching functions that will change the global button status when pressed or released - This is actuslly the hesrt of the program. When a button is not being pressed, nothing is happening (no loops). This makes the progrsm more battery efficient. - When a setWatch event is raised, the custom callbacks defined here will be called. These then fired as events to the current state/screen of the state mschine. - Some events, will result in the stste of the state machine chsnging, which is why the screen is redrswn after each button press. - */ const setMyWatch = (params) => { setWatch(() => { @@ -378,7 +354,7 @@ const setMyWatch = (params) => { */ const buttons = [ {bool : bottom_btn, label : "bottom",btn : BTN3}, - {bool : middle_btn, label : "mdiddle",btn : BTN2}, + {bool : middle_btn, label : "middle",btn : BTN2}, {bool : top_btn, label : "top",btn : BTN1}, {bool : left_btn, label : "left",btn : BTN4}, {bool : right_btn, label : "right",btn : BTN5} @@ -421,4 +397,4 @@ const drawScreen = (params) => { machine = Home; // instantiate the state machine at Home Bangle.drawWidgets(); // draw active widgets -drawScreen(machine.screen); // draw the screen +drawScreen(machine.screen); // draw the screen \ No newline at end of file From 42180a1770376ec1baeb37e433b902598b26784b Mon Sep 17 00:00:00 2001 From: Richard Hopkins Date: Mon, 1 Jun 2020 00:46:27 +0100 Subject: [PATCH 17/72] New screens, buttons and icons --- apps/BLEcontroller/README.md | 30 ++- apps/BLEcontroller/app.js | 369 +++++++++++++++++++++++++++++++++-- 2 files changed, 381 insertions(+), 18 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 049a5f824..237392e1e 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -2,25 +2,43 @@ A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. Amaze your friends by controlling your robot from your watch! -Commands are sent from the Controller to the BLE robot in a JSON format. +To keep the messages small, commands are sent from the Controller to the BLE robot in a text string. This is made up of a comma delimited string of the following elements: +* message number (3 characters) +* screen name (3 characters) +* object name (3 characters) +* value/status (3 characters) + +The combination of these variables will uniquely identify the status change requested from the watch to the robot that can then be programmed to respond appropriately. ## Usage -The application can be configured at will by chaning the definitions of the screens, events, icons and buttons. +The application can be configured at will by changing the definitions of the screens, events, icons and buttons. Most changes are possible via data, rather than code change. ## Features -In its default state, it has three screens that provide the ability to: -turn the robot on or off -turn on and off its voice and microphone -make the robot move by spinning left or right and moving forward and backwards +In its default state, it has nine screens that provide the ability to: +* select which robot to interact with (dog or dalek) + * for the dog the following functions are available: + * control movement via a joystick (forwards, backwards, spin left, spin right) + * turn on/off follow mode + * start a game of chess + * wake or sleep the robot + * wag its tail in two directions + * for the dalek, the user can: + * turn on or off face recognition + * make it say random phrases + * control the dalek's iris light and servo + * turn the dalek hover lights on or off + * turn the speaker on or off ## Controls The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. +I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) + ## Requests In the first instance, please consult my blog post on this application here. diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 3afae6b4b..6200600f1 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -80,11 +80,11 @@ const icons = [ }, { name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" }, { name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" }, { name: "forward", @@ -117,8 +117,60 @@ const icons = [ { name: "comms", data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + }, + { + name: "k9", + data: "gEBAP4B/AP4B/AP4B/AP4B/AKAADIf5N/IaIAJJv5LZLeIARffZNdD5JN/KLYATC65RbAGrHlJ/5P/JuYrRJfovNJf4BdAFJL/Jv5N/Jv5L1Jv5PvJv5L7Jv5PpAGpN/dv5HzAP4B/AP4B/AP4B/AP4B/ALg" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" } -]; + ]; /* finds icon data by name in the icon array and returns an image object*/ const drawIcon = (name) => { @@ -163,6 +215,114 @@ var turnRightBtn = { primary_icon: 'right', }; +var k9Btn = { + primary_colour: 0x653E, + primary_text: 'K9', + primary_icon: 'k9', + }; + +var dalekBtn = { + primary_colour: 0x33F9, + primary_text: 'Dalek', + primary_icon: 'dalek', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var happyBtn = { + primary_colour: 0x653E, + primary_text: 'Speak', + primary_icon: 'happy', + }; + +var sadBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'sad', + }; + +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var hoverBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'hover', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + var autoBtn = { primary_colour: 0xE9C7, primary_text: 'Stop', @@ -207,9 +367,16 @@ are defined as btn1, bt2 and bt3. The values are names from the icon array. */ const menuScreen = { - left: autoBtn, + left: k9Btn, + right: dalekBtn, +}; + +const k9MenuScreen = { + left: wakeBtn, right: joystickBtn, - btn1: "comms" + btn1: "pawn", + btn2: "wag_h", + btn3: "back" }; const joystickScreen = { @@ -220,12 +387,50 @@ const joystickScreen = { btn3: "back" }; +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + const commsScreen = { left: micBtn, right: spkBtn, btn3: "back" }; +const dalekMenuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", + btn3: "back" +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisBirisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: spkBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -270,15 +475,32 @@ const Home = new State({ screen: menuScreen, events: (event) => { if ((event.object == "right") && (event.status == "end")) { - transmit("Joystick", "joystick", "on"); - return Joystick; - } - if ((event.object == "top") && (event.status == "end")) { - return Comms; + return DalekMenu; } if ((event.object == "left") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "auto", onOff(status_auto.value)); + //status_auto.value = !status_auto.value; + //transmit(this.state, "auto", onOff(status_auto.value)); + //return this; + return K9Menu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const K9Menu = new State({ + state: "K9Menu", + screen: k9MenuScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "auto", onOff(status_wake.value)); return this; } transmit(this.state, event.object, event.status); @@ -286,6 +508,129 @@ const Home = new State({ } }); +const DalekMenu = new State({ + state: "DalekMenu", + screen: dalekMenuScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + return Speak; + } + if ((event.object == "left") && (event.status == "end")) { + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return K9Menu; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return K9Menu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "iris_light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "iris_servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "right") && (event.status == "end")) { + status_spk.value = !status_spk.value; + transmit(this.state, "iris_light", onOff(status_spk.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + + /* Joystick page state */ const Joystick = new State({ state: "Joystick", From 5bc70b474c0121bc26e7efdf4be07d6a3f876a4f Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 10:42:57 +0100 Subject: [PATCH 18/72] Merge didn't; t work --- apps.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps.json b/apps.json index 883a3cdf9..d266cd0c0 100644 --- a/apps.json +++ b/apps.json @@ -1768,11 +1768,10 @@ "storage": [ { "name": "jbm8b.app.js", "url": "app.js" }, { "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true } - ], + ] "version": "0.03" }, -{ - "id": "BLEcontroller", + { "id": "BLEcontroller", "name": "BLE Robot Controller with Joystick", "shortName": "BLE Controller", "icon": "BLEcontroller.png", @@ -1784,6 +1783,8 @@ "storage": [ { "name": "BLEcontroller.app.js", "url": "app.js" }, { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } + ] + }, { "id": "widviz", "name": "Widget Visibility Widget", "shortName":"Viz Widget", From 6aad4d8f93413c30c3d6b579040920a2c87124b8 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 11:27:51 +0100 Subject: [PATCH 19/72] Fixing JSON --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index d266cd0c0..6c0f50eca 100644 --- a/apps.json +++ b/apps.json @@ -1765,11 +1765,11 @@ "icon": "app.png", "description": "A simple fortune telling app", "tags": "game", + "version": "0.03", "storage": [ { "name": "jbm8b.app.js", "url": "app.js" }, { "name": "jbm8b.img", "url": "app-icon.js", "evaluate": true } - ] - "version": "0.03" + ] }, { "id": "BLEcontroller", "name": "BLE Robot Controller with Joystick", From 26d0fd32792b755c012223a982bf6b8b54b43dd1 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 11:40:59 +0100 Subject: [PATCH 20/72] Adding variable declarations and syntax error --- apps/BLEcontroller/app.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 6200600f1..7ba95589d 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -1,6 +1,6 @@ /* ========================================================== -Simple event based robot controller that enables robot +Simple event based robot controller that enables robot to switch into automatic or manual control modes. Behaviours are controlled via a simple finite state machine. In automatic mode the @@ -19,7 +19,7 @@ bottom_btn = false; msgNum = 0; // message number -/* +/* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button @@ -28,6 +28,12 @@ you should declare it and initiase it here */ var status_auto = {value: false}; var status_mic = {value: true}; var status_spk = {value: true}; +var status_face = {value: true}; +var status_chess = {value: false}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_wake = {value: false}; +var status_hover = {value: false}; /* trsnsmit message where @@ -415,7 +421,7 @@ const speakScreen = { const irisScreen = { left: irisBtn, - right: irisBirisLightBtn, + right: irisLightBtn, btn3: "back" }; @@ -431,9 +437,9 @@ const chessScreen = { btn3: "back" }; -/* base state definition +/* base state definition Each of the screens correspond to a state; -this class provides a constuctor for each +this class provides a constuctor for each of the states */ class State { @@ -605,7 +611,7 @@ const Iris = new State({ } transmit(this.state, event.object, event.status); return this; - } + } }); const Lights = new State({ @@ -627,7 +633,7 @@ const Lights = new State({ } transmit(this.state, event.object, event.status); return this; - } + } }); @@ -676,7 +682,7 @@ const onOff= status => status ? "on" : "off"; /* create watching functions that will change the global -button status when pressed or released +button status when pressed or released This is actuslly the hesrt of the program. When a button is not being pressed, nothing is happening (no loops). This makes the progrsm more battery efficient. @@ -684,7 +690,7 @@ When a setWatch event is raised, the custom callbacks defined here will be called. These then fired as events to the current state/screen of the state mschine. Some events, will result in the stste of the state machine -chsnging, which is why the screen is redrswn after each +chsnging, which is why the screen is redrswn after each button press. */ const setMyWatch = (params) => { @@ -742,4 +748,4 @@ const drawScreen = (params) => { machine = Home; // instantiate the state machine at Home Bangle.drawWidgets(); // draw active widgets -drawScreen(machine.screen); // draw the screen \ No newline at end of file +drawScreen(machine.screen); // draw the screen From a5cc710ef84f053b598fad8eb0c2e3834140d1c9 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 11:44:27 +0100 Subject: [PATCH 21/72] Syntax error --- apps/BLEcontroller/app.js | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 7ba95589d..2ad91ba54 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -580,18 +580,6 @@ const Tail = new State({ } }); -const Speak = new State({ - state: "Speak", - screen: speakScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - const Iris = new State({ state: "Iris", screen: irisScreen, From b929b5d0cbe903070f741510f4681e23333e3951 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:19:23 +0100 Subject: [PATCH 22/72] Splitting app into three variants --- apps/BLEcontroller/README.md | 32 +- apps/BLEcontroller/app-big.js | 739 ++++++++++++++++++++++++++++++++++ apps/BLEcontroller/app.js | 520 ++++-------------------- 3 files changed, 824 insertions(+), 467 deletions(-) create mode 100644 apps/BLEcontroller/app-big.js diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 237392e1e..56f1a2658 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,14 +1,18 @@ -# BLE Robot Controller with Joystick +# BLE Generic Controller with Joystick -A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. Amaze your friends by controlling your robot from your watch! +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. -To keep the messages small, commands are sent from the Controller to the BLE robot in a text string. This is made up of a comma delimited string of the following elements: +Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + +To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: * message number (3 characters) * screen name (3 characters) * object name (3 characters) * value/status (3 characters) -The combination of these variables will uniquely identify the status change requested from the watch to the robot that can then be programmed to respond appropriately. +The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. + +Gordon Williams' EspruinoHub is an excellent way to transform BLE advertisements into MQTT messages for further processing. ## Usage @@ -18,20 +22,12 @@ Most changes are possible via data, rather than code change. ## Features -In its default state, it has nine screens that provide the ability to: -* select which robot to interact with (dog or dalek) - * for the dog the following functions are available: - * control movement via a joystick (forwards, backwards, spin left, spin right) - * turn on/off follow mode - * start a game of chess - * wake or sleep the robot - * wag its tail in two directions - * for the dalek, the user can: - * turn on or off face recognition - * make it say random phrases - * control the dalek's iris light and servo - * turn the dalek hover lights on or off - * turn the speaker on or off +The default package contains three configurations: +* a simple home light and sockets controller UI (app.js) +* a robot controller UI with joystick (app-joy.js) +* a simple static assistant controller (app-ass.js) + +You can try out the other configurations by deleting app.js and renaming the file you want to app.js. ## Controls diff --git a/apps/BLEcontroller/app-big.js b/apps/BLEcontroller/app-big.js new file mode 100644 index 000000000..2ad91ba54 --- /dev/null +++ b/apps/BLEcontroller/app-big.js @@ -0,0 +1,739 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_mic = {value: true}; +var status_spk = {value: true}; +var status_face = {value: true}; +var status_chess = {value: false}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_wake = {value: false}; +var status_hover = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0.4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "mic_off", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Wf47/HJZLjHZ45RHrI7NHJYhLHqoZJA54hNHr5lTXL6vPSra5jKbo9REZrLRHa5DTXp47jAA7TTF7INLRqY7fdKavhXKo5te6wA==" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + }, + { + name: "k9", + data: "gEBAP4B/AP4B/AP4B/AP4B/AKAADIf5N/IaIAJJv5LZLeIARffZNdD5JN/KLYATC65RbAGrHlJ/5P/JuYrRJfovNJf4BdAFJL/Jv5N/Jv5L1Jv5PvJv5L7Jv5PpAGpN/dv5HzAP4B/AP4B/AP4B/AP4B/ALg" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var k9Btn = { + primary_colour: 0x653E, + primary_text: 'K9', + primary_icon: 'k9', + }; + +var dalekBtn = { + primary_colour: 0x33F9, + primary_text: 'Dalek', + primary_icon: 'dalek', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var happyBtn = { + primary_colour: 0x653E, + primary_text: 'Speak', + primary_icon: 'happy', + }; + +var sadBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'sad', + }; + +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var hoverBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'hover', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +var micBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'mic_off', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'mic_on', + value: status_mic + }; + +var spkBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'spk_off', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'spk_on', + value: status_spk + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ +const menuScreen = { + left: k9Btn, + right: dalekBtn, +}; + +const k9MenuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_h", + btn3: "back" +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + +const commsScreen = { + left: micBtn, + right: spkBtn, + btn3: "back" +}; + +const dalekMenuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", + btn3: "back" +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: spkBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the sppropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ +const Home = new State({ + state: "Home", + screen: menuScreen, + events: (event) => { + if ((event.object == "right") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "left") && (event.status == "end")) { + //status_auto.value = !status_auto.value; + //transmit(this.state, "auto", onOff(status_auto.value)); + //return this; + return K9Menu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const K9Menu = new State({ + state: "K9Menu", + screen: k9MenuScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "auto", onOff(status_wake.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const DalekMenu = new State({ + state: "DalekMenu", + screen: dalekMenuScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + return Speak; + } + if ((event.object == "left") && (event.status == "end")) { + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return K9Menu; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return K9Menu; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "iris_light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "iris_servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return DalekMenu; + } + if ((event.object == "right") && (event.status == "end")) { + status_spk.value = !status_spk.value; + transmit(this.state, "iris_light", onOff(status_spk.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Comms page state */ +const Comms = new State({ + state: "Comms", + screen: commsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "left") && (event.status == "end")) { + status_mic.value = !status_mic.value; + transmit(this.state, "mic", onOff(status_mic.value)); + return this; + } + if ((event.object == "right") && (event.status == "end")) { + status_spk.value = !status_spk.value; + transmit(this.state, "spk", onOff(status_spk.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,24,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 2ad91ba54..1b4775ef2 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -25,15 +25,10 @@ declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_auto = {value: false}; -var status_mic = {value: true}; -var status_spk = {value: true}; -var status_face = {value: true}; -var status_chess = {value: false}; -var status_iris_light = {value: false}; -var status_iris = {value: false}; -var status_wake = {value: false}; -var status_hover = {value: false}; +var status_printer = {value: false}; +var status_tv = {value: false}; +var status_light_hall = {value: false}; +var status_light_study = {value: false}; /* trsnsmit message where @@ -73,108 +68,12 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" - }, - { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" - }, - { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "spk_on", - data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" - }, - { - name: "spk_off", - data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" - }, - { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" - }, - { - name: "mic_off", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Wf47/HJZLjHZ45RHrI7NHJYhLHqoZJA54hNHr5lTXL6vPSra5jKbo9REZrLRHa5DTXp47jAA7TTF7INLRqY7fdKavhXKo5te6wA==" - }, - { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" - }, - { - name: "k9", - data: "gEBAP4B/AP4B/AP4B/AP4B/AKAADIf5N/IaIAJJv5LZLeIARffZNdD5JN/KLYATC65RbAGrHlJ/5P/JuYrRJfovNJf4BdAFJL/Jv5N/Jv5L1Jv5PvJv5L7Jv5PpAGpN/dv5HzAP4B/AP4B/AP4B/AP4B/ALg" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" - }, - { - name: "facerecog", - data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" - }, - { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" - }, - { - name: "happy", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" - }, - { - name: "sad", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" - }, - { - name: "hover", - data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + name: "switch", + data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" }, { name: "light", data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" - }, - { - name: "speak", - data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" } ]; @@ -203,164 +102,62 @@ The global variable should be declared at the start of the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var joystickBtn = { + +var lightBtn = { primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', + primary_text: 'Lights', + primary_icon: 'light', }; -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { +var socketsBtn = { primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', + primary_text: 'Sockets', + primary_icon: 'switch', }; -var k9Btn = { - primary_colour: 0x653E, - primary_text: 'K9', - primary_icon: 'k9', - }; - -var dalekBtn = { - primary_colour: 0x33F9, - primary_text: 'Dalek', - primary_icon: 'dalek', - }; - -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { - primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', - }; - -var happyBtn = { - primary_colour: 0x653E, - primary_text: 'Speak', - primary_icon: 'happy', - }; - -var sadBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'sad', - }; - -var speakBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'speak', - }; - -var faceBtn = { +var lightHallBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'facerecog', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'facerecog', - value: status_face - }; - -var chessBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'pawn', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess - }; - -var irisLightBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', + primary_text: 'Hall Off', primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', + secondary_text: 'Hall On', secondary_icon : 'light', - value: status_iris_light + value: status_light_hall }; -var irisBtn = { +var lightStudyBtn = { primary_colour: 0xE9C7, - primary_text: 'Closed', - primary_icon: 'sleep', + primary_text: 'Study Off', + primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Open', - secondary_icon : 'awake', - value: status_iris + secondary_text: 'Study On', + secondary_icon : 'light', + value: status_light_study +}; + +var socketTVBtn = { + primary_colour: 0xE9C7, + primary_text: 'TV Off', + primary_icon: 'switch', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'TV On', + secondary_icon : 'switch', + value: status_tv }; -var wakeBtn = { +var socketPrinterBtn = { primary_colour: 0xE9C7, - primary_text: 'Sleeping', - primary_icon: 'sleep', + primary_text: 'Printer Off', + primary_icon: 'switch', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Awake', - secondary_icon : 'awake', - value: status_wake - }; - -var hoverBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'hover', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'hover', - value: status_hover - }; - -var autoBtn = { - primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto - }; - -var micBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'mic_off', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'mic_on', - value: status_mic - }; - -var spkBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'spk_off', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'spk_on', - value: status_spk - }; + secondary_text: 'Printer On', + secondary_icon : 'switch', + value: status_printer +}; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -372,68 +169,20 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ -const menuScreen = { - left: k9Btn, - right: dalekBtn, -}; - -const k9MenuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_h", - btn3: "back" -}; - -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", - btn3: "back" -}; - -const tailScreen = { - left: tailHBtn, - right: tailVBtn, - btn3: "back" -}; - -const commsScreen = { - left: micBtn, - right: spkBtn, - btn3: "back" -}; - -const dalekMenuScreen = { - left: faceBtn, - right: speakBtn, - btn1: "hover", - btn2: "light", - btn3: "back" -}; - -const speakScreen = { - left: happyBtn, - right: sadBtn, - btn3: "back" -}; - -const irisScreen = { - left: irisBtn, - right: irisLightBtn, - btn3: "back" +const homeScreen = { + left: lightsBtn, + right: socketsBtn, }; const lightsScreen = { - left: hoverBtn, - right: spkBtn, + left: lightHallBtn, + right: lightStudyBtn, btn3: "back" }; -const chessScreen = { - left: chessBtn, - right: autoBtn, +const socketsScreen = { + left: socketTVBtn, + right: socketPrinterBtn, btn3: "back" }; @@ -478,145 +227,34 @@ inversed and the new value transmitted. /* The Home State/Page is where the application beings */ const Home = new State({ state: "Home", - screen: menuScreen, + screen: homeScreen, events: (event) => { if ((event.object == "right") && (event.status == "end")) { - return DalekMenu; + return SocketsMenu; } if ((event.object == "left") && (event.status == "end")) { - //status_auto.value = !status_auto.value; - //transmit(this.state, "auto", onOff(status_auto.value)); - //return this; - return K9Menu; + return LightsMenu; } transmit(this.state, event.object, event.status); return this; } }); -const K9Menu = new State({ - state: "K9Menu", - screen: k9MenuScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - return Joystick; - } - if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "auto", onOff(status_wake.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const DalekMenu = new State({ - state: "DalekMenu", - screen: dalekMenuScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - return Speak; - } - if ((event.object == "left") && (event.status == "end")) { - status_face.value = !status_face.value; - transmit(this.state, "face", onOff(status_face.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Speak = new State({ - state: "Speak", - screen: speakScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Chess = new State({ - state: "Chess", - screen: chessScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return K9Menu; - } - if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Tail = new State({ - state: "Tail", - screen: tailScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return K9Menu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Iris = new State({ - state: "Iris", - screen: irisScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; - } - if ((event.object == "right") && (event.status == "end")) { - status_iris_light.value = !status_iris_light.value; - transmit(this.state, "iris_light", onOff(status_iris_light.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_iris.value = !status_iris.value; - transmit(this.state, "iris_servo", onOff(status_iris.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Lights = new State({ - state: "Lights", +const LightsMenu = new State({ + state: "LightsMenu", screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; + return Home; } if ((event.object == "right") && (event.status == "end")) { - status_spk.value = !status_spk.value; - transmit(this.state, "iris_light", onOff(status_spk.value)); + status_light_study.value = !status_light_study.value; + transmit(this.state, "auto", onOff(status_light_study.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_hover.value = !status_hover.value; - transmit(this.state, "hover", onOff(status_hover.value)); + status_light_hall.value = !status_light_hall.value; + transmit(this.state, "auto", onOff(status_light_hall.value)); return this; } transmit(this.state, event.object, event.status); @@ -624,42 +262,26 @@ const Lights = new State({ } }); - -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, +const SocketsMenu = new State({ + state: "SocketsMenu", + screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* Comms page state */ -const Comms = new State({ - state: "Comms", - screen: commsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "left") && (event.status == "end")) { - status_mic.value = !status_mic.value; - transmit(this.state, "mic", onOff(status_mic.value)); - return this; + return Home; } if ((event.object == "right") && (event.status == "end")) { - status_spk.value = !status_spk.value; - transmit(this.state, "spk", onOff(status_spk.value)); + status_printer.value = !status_printer.value; + transmit(this.state, "auto", onOff(status_printer.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_tv.value = !status_tv.value; + transmit(this.state, "auto", onOff(status_tv.value)); return this; } transmit(this.state, event.object, event.status); return this; - } + } }); /* translate button status into english */ From 0b7200eda7a444030ea02124486fc3a5214e34f6 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:20:46 +0100 Subject: [PATCH 23/72] Minor README change --- apps/BLEcontroller/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 56f1a2658..0929a9fd7 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,4 +1,4 @@ -# BLE Generic Controller with Joystick +# BLE Customisable Controller with Joystick A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. From 60b0fee49d230554b5c09a0e870173b194ec0b61 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:22:38 +0100 Subject: [PATCH 24/72] Change to app description --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 9ba610101..79923cab2 100644 --- a/apps.json +++ b/apps.json @@ -1772,11 +1772,11 @@ ] }, { "id": "BLEcontroller", - "name": "BLE Robot Controller with Joystick", + "name": "BLE Customisable Controller with Joystick", "shortName": "BLE Controller", "icon": "BLEcontroller.png", "version": "0.01", - "description": "A configurable controller for BLE robots, with a basic four direction joystick. Easy to customise and add your own menus.", + "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", "tags": "tool,bluetooth", "readme": "README.md", "allow_emulator":true, From 03f4f1da8bca0474b371e8bb68728479faf4d09c Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:27:02 +0100 Subject: [PATCH 25/72] Bug fix --- apps/BLEcontroller/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 1b4775ef2..96f56efce 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -170,7 +170,7 @@ are defined as btn1, bt2 and bt3. The values are names from the icon array. */ const homeScreen = { - left: lightsBtn, + left: lightBtn, right: socketsBtn, }; From b9f0907e5a1a371038f56e5a57a5d69b015bbc02 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:36:03 +0100 Subject: [PATCH 26/72] Added back icon --- apps/BLEcontroller/README.md | 2 +- apps/BLEcontroller/app.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 0929a9fd7..d66ea9557 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,4 +1,4 @@ -# BLE Customisable Controller with Joystick +# BLE Customisable Controller with Joystick A A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 96f56efce..0ae900b9b 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -74,6 +74,10 @@ const icons = [ { name: "light", data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" } ]; @@ -220,7 +224,7 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the sppropiate status object is +For toggle buttons, the value of the appropiate status object is inversed and the new value transmitted. */ From 9f1b61d2d9211fed78e5e405023d46fbbfcee876 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 14:41:52 +0100 Subject: [PATCH 27/72] Minor bug fix --- apps/BLEcontroller/README.md | 2 +- apps/BLEcontroller/app.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index d66ea9557..0929a9fd7 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -1,4 +1,4 @@ -# BLE Customisable Controller with Joystick A +# BLE Customisable Controller with Joystick A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 0ae900b9b..fc7d7dbb7 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -268,7 +268,7 @@ const LightsMenu = new State({ const SocketsMenu = new State({ state: "SocketsMenu", - screen: lightsScreen, + screen: socketsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; From 615f8c8fcefc3a1d71c5f63b3be1f0659fb16e56 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:18:48 +0100 Subject: [PATCH 28/72] Update transmitted values --- apps/BLEcontroller/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index fc7d7dbb7..fd07d73f9 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -253,12 +253,12 @@ const LightsMenu = new State({ } if ((event.object == "right") && (event.status == "end")) { status_light_study.value = !status_light_study.value; - transmit(this.state, "auto", onOff(status_light_study.value)); + transmit(this.state, "study", onOff(status_light_study.value)); return this; } if ((event.object == "left") && (event.status == "end")) { status_light_hall.value = !status_light_hall.value; - transmit(this.state, "auto", onOff(status_light_hall.value)); + transmit(this.state, "hall", onOff(status_light_hall.value)); return this; } transmit(this.state, event.object, event.status); @@ -275,12 +275,12 @@ const SocketsMenu = new State({ } if ((event.object == "right") && (event.status == "end")) { status_printer.value = !status_printer.value; - transmit(this.state, "auto", onOff(status_printer.value)); + transmit(this.state, "printer", onOff(status_printer.value)); return this; } if ((event.object == "left") && (event.status == "end")) { status_tv.value = !status_tv.value; - transmit(this.state, "auto", onOff(status_tv.value)); + transmit(this.state, "tv", onOff(status_tv.value)); return this; } transmit(this.state, event.object, event.status); From 7cf0154259994b84a9dd5944b8bb8eb42d7c258d Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:21:08 +0100 Subject: [PATCH 29/72] Adding widgets back in --- apps/BLEcontroller/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index fd07d73f9..3f18ffa1c 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -313,6 +313,7 @@ const setMyWatch = (params) => { machine = machine.events({object: params.label, status: startEnd(params.bool)}); drawScreen(machine.screen); }, params.btn, {repeat:true, edge:"both"}); + drawWidgets(); }; /* object array used to set up the watching functions From 6962fd01d66b451c986c1a8b3eb43abfd2e9f18c Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:24:22 +0100 Subject: [PATCH 30/72] Syntax error --- apps/BLEcontroller/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 3f18ffa1c..01a2c78c8 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -313,7 +313,7 @@ const setMyWatch = (params) => { machine = machine.events({object: params.label, status: startEnd(params.bool)}); drawScreen(machine.screen); }, params.btn, {repeat:true, edge:"both"}); - drawWidgets(); + Bangle.drawWidgets(); }; /* object array used to set up the watching functions From fdbf4300ef20b9060ee4d1759d52c51936d73f7b Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:47:00 +0100 Subject: [PATCH 31/72] Change transmission frequency --- apps/BLEcontroller/app.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 01a2c78c8..8cb611273 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -19,6 +19,7 @@ bottom_btn = false; msgNum = 0; // message number +NRF.setConnectionInterval(100) /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button From 39f62c1ab7c2c018e288c724ae69fbd5f0084dca Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 15:49:19 +0100 Subject: [PATCH 32/72] Try once at beginning of app --- apps/BLEcontroller/app.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 8cb611273..7fd908d59 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -20,6 +20,8 @@ bottom_btn = false; msgNum = 0; // message number NRF.setConnectionInterval(100) +Bangle.loadWidgets() +Bangle.drawWidgets() /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button @@ -314,7 +316,6 @@ const setMyWatch = (params) => { machine = machine.events({object: params.label, status: startEnd(params.bool)}); drawScreen(machine.screen); }, params.btn, {repeat:true, edge:"both"}); - Bangle.drawWidgets(); }; /* object array used to set up the watching functions From 5ca81d9bfbcc0c8351c3bc4ed2f25c186cb4fbdc Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 16:01:50 +0100 Subject: [PATCH 33/72] Tidy up --- apps/BLEcontroller/app.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 7fd908d59..6f8b70e1b 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -19,9 +19,9 @@ bottom_btn = false; msgNum = 0; // message number -NRF.setConnectionInterval(100) -Bangle.loadWidgets() -Bangle.drawWidgets() +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button From e8f8703b36cb4688e2b04cddd0480c73ace3bcff Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 16:06:10 +0100 Subject: [PATCH 34/72] Cosmetic change to give gap to widgets --- apps/BLEcontroller/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 6f8b70e1b..ba172b047 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -344,7 +344,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,24,119+x, 239); + g.fillRect(0+x,28,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); From 7b6fe2f0d2eaa6a3a49d55a8f32ed30c78e1646e Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 17:30:19 +0100 Subject: [PATCH 35/72] Major refactoring to three apps --- apps.json | 2 +- apps/BLEcontroller/{app-big.js => app-ex2.js} | 342 +------------- apps/BLEcontroller/app-joy.js | 441 ++++++++++++++++++ 3 files changed, 466 insertions(+), 319 deletions(-) rename apps/BLEcontroller/{app-big.js => app-ex2.js} (62%) create mode 100644 apps/BLEcontroller/app-joy.js diff --git a/apps.json b/apps.json index 79923cab2..ac0decf97 100644 --- a/apps.json +++ b/apps.json @@ -1779,7 +1779,7 @@ "description": "A configurable controller for BLE devices and robots, with a basic four direction joystick. Designed to be easy to customise so you can add your own menus.", "tags": "tool,bluetooth", "readme": "README.md", - "allow_emulator":true, + "allow_emulator":false, "storage": [ { "name": "BLEcontroller.app.js", "url": "app.js" }, { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } diff --git a/apps/BLEcontroller/app-big.js b/apps/BLEcontroller/app-ex2.js similarity index 62% rename from apps/BLEcontroller/app-big.js rename to apps/BLEcontroller/app-ex2.js index 2ad91ba54..a24d7805b 100644 --- a/apps/BLEcontroller/app-big.js +++ b/apps/BLEcontroller/app-ex2.js @@ -25,15 +25,12 @@ declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_auto = {value: false}; -var status_mic = {value: true}; var status_spk = {value: true}; var status_face = {value: true}; -var status_chess = {value: false}; var status_iris_light = {value: false}; var status_iris = {value: false}; -var status_wake = {value: false}; var status_hover = {value: false}; +var status_dome = {value: false}; /* trsnsmit message where @@ -72,34 +69,6 @@ Add an additional element to the icons array with a unique name and the data from the Image Object */ const icons = [ - { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" - }, - { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" - }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" @@ -111,30 +80,6 @@ const icons = [ { name: "spk_off", data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" - }, - { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" - }, - { - name: "mic_off", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Wf47/HJZLjHZ45RHrI7NHJYhLHqoZJA54hNHr5lTXL6vPSra5jKbo9REZrLRHa5DTXp47jAA7TTF7INLRqY7fdKavhXKo5te6wA==" - }, - { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" - }, - { - name: "k9", - data: "gEBAP4B/AP4B/AP4B/AP4B/AKAADIf5N/IaIAJJv5LZLeIARffZNdD5JN/KLYATC65RbAGrHlJ/5P/JuYrRJfovNJf4BdAFJL/Jv5N/Jv5L1Jv5PvJv5L7Jv5PpAGpN/dv5HzAP4B/AP4B/AP4B/AP4B/ALg" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" }, { name: "facerecog", @@ -148,14 +93,6 @@ const icons = [ name: "awake", data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" }, - { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" - }, - { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" - }, { name: "happy", data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" @@ -175,6 +112,10 @@ const icons = [ { name: "speak", data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" } ]; @@ -203,47 +144,6 @@ The global variable should be declared at the start of the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var joystickBtn = { - primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', - }; - -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { - primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', - }; - -var k9Btn = { - primary_colour: 0x653E, - primary_text: 'K9', - primary_icon: 'k9', - }; - -var dalekBtn = { - primary_colour: 0x33F9, - primary_text: 'Dalek', - primary_icon: 'dalek', - }; - -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { - primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', - }; var happyBtn = { primary_colour: 0x653E, @@ -274,17 +174,6 @@ var faceBtn = { value: status_face }; -var chessBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'pawn', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess - }; - var irisLightBtn = { primary_colour: 0xE9C7, primary_text: 'Off', @@ -307,17 +196,6 @@ var irisBtn = { value: status_iris }; -var wakeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Sleeping', - primary_icon: 'sleep', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Awake', - secondary_icon : 'awake', - value: status_wake - }; - var hoverBtn = { primary_colour: 0xE9C7, primary_text: 'Off', @@ -329,38 +207,16 @@ var hoverBtn = { value: status_hover }; -var autoBtn = { - primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto - }; - -var micBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'mic_off', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'mic_on', - value: status_mic - }; - -var spkBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'spk_off', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'spk_on', - value: status_spk - }; + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -372,40 +228,8 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ + const menuScreen = { - left: k9Btn, - right: dalekBtn, -}; - -const k9MenuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_h", - btn3: "back" -}; - -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", - btn3: "back" -}; - -const tailScreen = { - left: tailHBtn, - right: tailVBtn, - btn3: "back" -}; - -const commsScreen = { - left: micBtn, - right: spkBtn, - btn3: "back" -}; - -const dalekMenuScreen = { left: faceBtn, right: speakBtn, btn1: "hover", @@ -427,13 +251,7 @@ const irisScreen = { const lightsScreen = { left: hoverBtn, - right: spkBtn, - btn3: "back" -}; - -const chessScreen = { - left: chessBtn, - right: autoBtn, + right: domeBtn, btn3: "back" }; @@ -476,51 +294,11 @@ inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ + const Home = new State({ - state: "Home", + state: "DalekMenu", screen: menuScreen, events: (event) => { - if ((event.object == "right") && (event.status == "end")) { - return DalekMenu; - } - if ((event.object == "left") && (event.status == "end")) { - //status_auto.value = !status_auto.value; - //transmit(this.state, "auto", onOff(status_auto.value)); - //return this; - return K9Menu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const K9Menu = new State({ - state: "K9Menu", - screen: k9MenuScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - return Joystick; - } - if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "auto", onOff(status_wake.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const DalekMenu = new State({ - state: "DalekMenu", - screen: dalekMenuScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } if ((event.object == "right") && (event.status == "end")) { return Speak; } @@ -539,41 +317,7 @@ const Speak = new State({ screen: speakScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Chess = new State({ - state: "Chess", - screen: chessScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return K9Menu; - } - if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Tail = new State({ - state: "Tail", - screen: tailScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return K9Menu; + return Home; } transmit(this.state, event.object, event.status); return this; @@ -585,7 +329,7 @@ const Iris = new State({ screen: irisScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; + return Home; } if ((event.object == "right") && (event.status == "end")) { status_iris_light.value = !status_iris_light.value; @@ -607,11 +351,11 @@ const Lights = new State({ screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return DalekMenu; + return Home; } if ((event.object == "right") && (event.status == "end")) { - status_spk.value = !status_spk.value; - transmit(this.state, "iris_light", onOff(status_spk.value)); + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); return this; } if ((event.object == "left") && (event.status == "end")) { @@ -624,44 +368,6 @@ const Lights = new State({ } }); - -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* Comms page state */ -const Comms = new State({ - state: "Comms", - screen: commsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "left") && (event.status == "end")) { - status_mic.value = !status_mic.value; - transmit(this.state, "mic", onOff(status_mic.value)); - return this; - } - if ((event.object == "right") && (event.status == "end")) { - status_spk.value = !status_spk.value; - transmit(this.state, "spk", onOff(status_spk.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - /* translate button status into english */ const startEnd = status => status ? "start" : "end"; diff --git a/apps/BLEcontroller/app-joy.js b/apps/BLEcontroller/app-joy.js new file mode 100644 index 000000000..66bad3934 --- /dev/null +++ b/apps/BLEcontroller/app-joy.js @@ -0,0 +1,441 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0.4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ +const menuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_h", + btn3: "back" +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the appropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ + +const Home = new State({ + state: "K9Menu", + screen: menuScreen, + events: (event) => { + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,28,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen From 1e98a6d73b42e1aad89f0378f9105ef46516c010 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 17:42:46 +0100 Subject: [PATCH 36/72] Update to READ.ME --- apps/BLEcontroller/README.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 0929a9fd7..3f9dfa6b8 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -4,6 +4,8 @@ A highly customisable state machine driven user interface that will communicate Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + + To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: * message number (3 characters) * screen name (3 characters) @@ -12,7 +14,8 @@ To keep the messages small, commands are sent from the Controller to the BLE tar The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. -Gordon Williams' EspruinoHub is an excellent way to transform BLE advertisements into MQTT messages for further processing. +Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) +/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# ## Usage @@ -25,9 +28,11 @@ Most changes are possible via data, rather than code change. The default package contains three configurations: * a simple home light and sockets controller UI (app.js) * a robot controller UI with joystick (app-joy.js) -* a simple static assistant controller (app-ass.js) +* a simple static assistant controller (app-ex2.js) -You can try out the other configurations by deleting app.js and renaming the file you want to app.js. +You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. + +I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. ## Controls @@ -37,7 +42,7 @@ I have used the convention of red/green for buttons that are switches and blue b ## Requests -In the first instance, please consult my blog post on this application here. +In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) ## Creator From 262b12277761cfe0e7cae56bf8ac8ee45644d218 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 17:55:11 +0100 Subject: [PATCH 37/72] Change video format --- apps/BLEcontroller/README.md | 2 +- apps/BLEcontroller/video.png | Bin 0 -> 178721 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 apps/BLEcontroller/video.png diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 3f9dfa6b8..ad2d5aad2 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -4,7 +4,7 @@ A highly customisable state machine driven user interface that will communicate Amaze your friends by controlling your robot, your house or any other BLE device from your watch! - +[![Video of watch and robot](./video.png)](https://www.youtube.com/embed/acQxcoFe0W0 "Control your robot from your Watch") To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: * message number (3 characters) diff --git a/apps/BLEcontroller/video.png b/apps/BLEcontroller/video.png new file mode 100644 index 0000000000000000000000000000000000000000..bd25e26a240e53ad6b09e0ba5eb1ab950f966d2b GIT binary patch literal 178721 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�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 Date: Mon, 1 Jun 2020 17:57:35 +0100 Subject: [PATCH 38/72] Reverting because it worked! --- apps/BLEcontroller/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index ad2d5aad2..3f9dfa6b8 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -4,7 +4,7 @@ A highly customisable state machine driven user interface that will communicate Amaze your friends by controlling your robot, your house or any other BLE device from your watch! -[![Video of watch and robot](./video.png)](https://www.youtube.com/embed/acQxcoFe0W0 "Control your robot from your Watch") + To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: * message number (3 characters) From 93f818eef492ac1d8da1cf1c32ed6f835fa4feb2 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 18:11:18 +0100 Subject: [PATCH 39/72] Documenting message size --- apps/BLEcontroller/Bangle.code-workspace | 7 +++++++ apps/BLEcontroller/README.md | 8 ++++---- apps/BLEcontroller/app-ex2.js | 2 +- apps/BLEcontroller/app-joy.js | 2 +- apps/BLEcontroller/app.js | 2 +- 5 files changed, 14 insertions(+), 7 deletions(-) create mode 100644 apps/BLEcontroller/Bangle.code-workspace diff --git a/apps/BLEcontroller/Bangle.code-workspace b/apps/BLEcontroller/Bangle.code-workspace new file mode 100644 index 000000000..90587e88f --- /dev/null +++ b/apps/BLEcontroller/Bangle.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "/Users/hopkira/Documents/BangleApps" + } + ] +} \ No newline at end of file diff --git a/apps/BLEcontroller/README.md b/apps/BLEcontroller/README.md index 3f9dfa6b8..c02e29543 100644 --- a/apps/BLEcontroller/README.md +++ b/apps/BLEcontroller/README.md @@ -7,10 +7,10 @@ Amaze your friends by controlling your robot, your house or any other BLE device To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: -* message number (3 characters) -* screen name (3 characters) -* object name (3 characters) -* value/status (3 characters) +* message number (up to the least significant four digits) +* screen name (up to four characters) +* object name (up to four characters) +* value/status (up to four characters) The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. diff --git a/apps/BLEcontroller/app-ex2.js b/apps/BLEcontroller/app-ex2.js index a24d7805b..4ed3a5eeb 100644 --- a/apps/BLEcontroller/app-ex2.js +++ b/apps/BLEcontroller/app-ex2.js @@ -45,7 +45,7 @@ const transmit = (state,object,status) => { n: msgNum.toString().slice(-4), s: state.substr(0,4), o: object.substr(0,4), - v: status.substr(0.4), + v: status.substr(0,4), }; message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; NRF.setAdvertising({},{ diff --git a/apps/BLEcontroller/app-joy.js b/apps/BLEcontroller/app-joy.js index 66bad3934..8da1aadcb 100644 --- a/apps/BLEcontroller/app-joy.js +++ b/apps/BLEcontroller/app-joy.js @@ -45,7 +45,7 @@ const transmit = (state,object,status) => { n: msgNum.toString().slice(-4), s: state.substr(0,4), o: object.substr(0,4), - v: status.substr(0.4), + v: status.substr(0,4), }; message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; NRF.setAdvertising({},{ diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index ba172b047..c8217988c 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -46,7 +46,7 @@ const transmit = (state,object,status) => { n: msgNum.toString().slice(-4), s: state.substr(0,4), o: object.substr(0,4), - v: status.substr(0.4), + v: status.substr(0,4), }; message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; NRF.setAdvertising({},{ From 5c2bf298502a2652874f982098c6de7c73dd31dd Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 18:42:35 +0100 Subject: [PATCH 40/72] Switching to Dalek app --- apps/BLEcontroller/app.js | 255 ++++++++++++------ .../{app-ex2.js => app.js.old.js} | 255 ++++++------------ 2 files changed, 255 insertions(+), 255 deletions(-) rename apps/BLEcontroller/{app-ex2.js => app.js.old.js} (65%) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index c8217988c..4ed3a5eeb 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -19,19 +19,18 @@ bottom_btn = false; msgNum = 0; // message number -NRF.setConnectionInterval(100); -Bangle.loadWidgets(); -Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_printer = {value: false}; -var status_tv = {value: false}; -var status_light_hall = {value: false}; -var status_light_study = {value: false}; +var status_spk = {value: true}; +var status_face = {value: true}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_hover = {value: false}; +var status_dome = {value: false}; /* trsnsmit message where @@ -71,16 +70,52 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "switch", - data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" }, { name: "light", data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" }, { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" } ]; @@ -110,61 +145,78 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var lightBtn = { +var happyBtn = { primary_colour: 0x653E, - primary_text: 'Lights', - primary_icon: 'light', + primary_text: 'Speak', + primary_icon: 'happy', }; -var socketsBtn = { +var sadBtn = { primary_colour: 0x33F9, - primary_text: 'Sockets', - primary_icon: 'switch', + primary_text: 'Speak', + primary_icon: 'sad', }; -var lightHallBtn = { +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { primary_colour: 0xE9C7, - primary_text: 'Hall Off', + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Hall On', + secondary_text: 'On', secondary_icon : 'light', - value: status_light_hall + value: status_iris_light }; -var lightStudyBtn = { +var irisBtn = { primary_colour: 0xE9C7, - primary_text: 'Study Off', - primary_icon: 'light', + primary_text: 'Closed', + primary_icon: 'sleep', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Study On', - secondary_icon : 'light', - value: status_light_study -}; - -var socketTVBtn = { - primary_colour: 0xE9C7, - primary_text: 'TV Off', - primary_icon: 'switch', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'TV On', - secondary_icon : 'switch', - value: status_tv + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris }; -var socketPrinterBtn = { +var hoverBtn = { primary_colour: 0xE9C7, - primary_text: 'Printer Off', - primary_icon: 'switch', + primary_text: 'Off', + primary_icon: 'hover', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Printer On', - secondary_icon : 'switch', - value: status_printer -}; + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -176,20 +228,30 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ -const homeScreen = { - left: lightBtn, - right: socketsBtn, -}; -const lightsScreen = { - left: lightHallBtn, - right: lightStudyBtn, +const menuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", btn3: "back" }; -const socketsScreen = { - left: socketTVBtn, - right: socketPrinterBtn, +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: domeBtn, btn3: "back" }; @@ -227,63 +289,78 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the appropiate status object is +For toggle buttons, the value of the sppropiate status object is inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ + const Home = new State({ - state: "Home", - screen: homeScreen, + state: "DalekMenu", + screen: menuScreen, events: (event) => { if ((event.object == "right") && (event.status == "end")) { - return SocketsMenu; + return Speak; } if ((event.object == "left") && (event.status == "end")) { - return LightsMenu; + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; } transmit(this.state, event.object, event.status); return this; } }); -const LightsMenu = new State({ - state: "LightsMenu", +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "iris_light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "iris_servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } if ((event.object == "right") && (event.status == "end")) { - status_light_study.value = !status_light_study.value; - transmit(this.state, "study", onOff(status_light_study.value)); + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_light_hall.value = !status_light_hall.value; - transmit(this.state, "hall", onOff(status_light_hall.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const SocketsMenu = new State({ - state: "SocketsMenu", - screen: socketsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_printer.value = !status_printer.value; - transmit(this.state, "printer", onOff(status_printer.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_tv.value = !status_tv.value; - transmit(this.state, "tv", onOff(status_tv.value)); + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); return this; } transmit(this.state, event.object, event.status); @@ -344,7 +421,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,28,119+x, 239); + g.fillRect(0+x,24,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); diff --git a/apps/BLEcontroller/app-ex2.js b/apps/BLEcontroller/app.js.old.js similarity index 65% rename from apps/BLEcontroller/app-ex2.js rename to apps/BLEcontroller/app.js.old.js index 4ed3a5eeb..c8217988c 100644 --- a/apps/BLEcontroller/app-ex2.js +++ b/apps/BLEcontroller/app.js.old.js @@ -19,18 +19,19 @@ bottom_btn = false; msgNum = 0; // message number +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_spk = {value: true}; -var status_face = {value: true}; -var status_iris_light = {value: false}; -var status_iris = {value: false}; -var status_hover = {value: false}; -var status_dome = {value: false}; +var status_printer = {value: false}; +var status_tv = {value: false}; +var status_light_hall = {value: false}; +var status_light_study = {value: false}; /* trsnsmit message where @@ -70,52 +71,16 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "spk_on", - data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" - }, - { - name: "spk_off", - data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" - }, - { - name: "facerecog", - data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "happy", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" - }, - { - name: "sad", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" - }, - { - name: "hover", - data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + name: "switch", + data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" }, { name: "light", data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" }, { - name: "speak", - data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" } ]; @@ -145,78 +110,61 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var happyBtn = { +var lightBtn = { primary_colour: 0x653E, - primary_text: 'Speak', - primary_icon: 'happy', + primary_text: 'Lights', + primary_icon: 'light', }; -var sadBtn = { +var socketsBtn = { primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'sad', + primary_text: 'Sockets', + primary_icon: 'switch', }; -var speakBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'speak', - }; - -var faceBtn = { +var lightHallBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'facerecog', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'facerecog', - value: status_face - }; - -var irisLightBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', + primary_text: 'Hall Off', primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', + secondary_text: 'Hall On', secondary_icon : 'light', - value: status_iris_light + value: status_light_hall }; -var irisBtn = { +var lightStudyBtn = { primary_colour: 0xE9C7, - primary_text: 'Closed', - primary_icon: 'sleep', + primary_text: 'Study Off', + primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Open', - secondary_icon : 'awake', - value: status_iris - }; + secondary_text: 'Study On', + secondary_icon : 'light', + value: status_light_study +}; -var hoverBtn = { +var socketTVBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'hover', + primary_text: 'TV Off', + primary_icon: 'switch', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'hover', - value: status_hover + secondary_text: 'TV On', + secondary_icon : 'switch', + value: status_tv }; - var domeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'dalek', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'dalek', - value: status_dome - }; +var socketPrinterBtn = { + primary_colour: 0xE9C7, + primary_text: 'Printer Off', + primary_icon: 'switch', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Printer On', + secondary_icon : 'switch', + value: status_printer +}; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -228,30 +176,20 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ - -const menuScreen = { - left: faceBtn, - right: speakBtn, - btn1: "hover", - btn2: "light", - btn3: "back" -}; - -const speakScreen = { - left: happyBtn, - right: sadBtn, - btn3: "back" -}; - -const irisScreen = { - left: irisBtn, - right: irisLightBtn, - btn3: "back" +const homeScreen = { + left: lightBtn, + right: socketsBtn, }; const lightsScreen = { - left: hoverBtn, - right: domeBtn, + left: lightHallBtn, + right: lightStudyBtn, + btn3: "back" +}; + +const socketsScreen = { + left: socketTVBtn, + right: socketPrinterBtn, btn3: "back" }; @@ -289,78 +227,63 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the sppropiate status object is +For toggle buttons, the value of the appropiate status object is inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ - const Home = new State({ - state: "DalekMenu", - screen: menuScreen, + state: "Home", + screen: homeScreen, events: (event) => { if ((event.object == "right") && (event.status == "end")) { - return Speak; + return SocketsMenu; } if ((event.object == "left") && (event.status == "end")) { - status_face.value = !status_face.value; - transmit(this.state, "face", onOff(status_face.value)); - return this; + return LightsMenu; } transmit(this.state, event.object, event.status); return this; } }); -const Speak = new State({ - state: "Speak", - screen: speakScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Iris = new State({ - state: "Iris", - screen: irisScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_iris_light.value = !status_iris_light.value; - transmit(this.state, "iris_light", onOff(status_iris_light.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_iris.value = !status_iris.value; - transmit(this.state, "iris_servo", onOff(status_iris.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Lights = new State({ - state: "Lights", +const LightsMenu = new State({ + state: "LightsMenu", screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } if ((event.object == "right") && (event.status == "end")) { - status_dome.value = !status_dome.value; - transmit(this.state, "dome", onOff(status_dome.value)); + status_light_study.value = !status_light_study.value; + transmit(this.state, "study", onOff(status_light_study.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_hover.value = !status_hover.value; - transmit(this.state, "hover", onOff(status_hover.value)); + status_light_hall.value = !status_light_hall.value; + transmit(this.state, "hall", onOff(status_light_hall.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const SocketsMenu = new State({ + state: "SocketsMenu", + screen: socketsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_printer.value = !status_printer.value; + transmit(this.state, "printer", onOff(status_printer.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_tv.value = !status_tv.value; + transmit(this.state, "tv", onOff(status_tv.value)); return this; } transmit(this.state, event.object, event.status); @@ -421,7 +344,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,24,119+x, 239); + g.fillRect(0+x,28,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); From 189633e966d9d9a0bd21d89b2eed9ddc195aeaa3 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 18:59:59 +0100 Subject: [PATCH 41/72] Modifying Home menu --- apps/BLEcontroller/app.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 4ed3a5eeb..d318994f1 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -234,7 +234,6 @@ const menuScreen = { right: speakBtn, btn1: "hover", btn2: "light", - btn3: "back" }; const speakScreen = { @@ -299,6 +298,12 @@ const Home = new State({ state: "DalekMenu", screen: menuScreen, events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Lights; + } + if ((event.object == "middle") && (event.status == "end")) { + return Iris; + } if ((event.object == "right") && (event.status == "end")) { return Speak; } From c08303390ab098add4f703f59629aec2fced316d Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 19:16:03 +0100 Subject: [PATCH 42/72] Distinguish between iris controls --- apps/BLEcontroller/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index d318994f1..27e629d5d 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -338,12 +338,12 @@ const Iris = new State({ } if ((event.object == "right") && (event.status == "end")) { status_iris_light.value = !status_iris_light.value; - transmit(this.state, "iris_light", onOff(status_iris_light.value)); + transmit(this.state, "light", onOff(status_iris_light.value)); return this; } if ((event.object == "left") && (event.status == "end")) { status_iris.value = !status_iris.value; - transmit(this.state, "iris_servo", onOff(status_iris.value)); + transmit(this.state, "servo", onOff(status_iris.value)); return this; } transmit(this.state, event.object, event.status); From 07310e35364a7f6904d6e3942dcd313fd39ea7e2 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 19:36:21 +0100 Subject: [PATCH 43/72] Testing joystick variant --- apps/BLEcontroller/{app-joy.js => app-ex2.js} | 287 +++++++++--------- apps/BLEcontroller/app.js | 287 +++++++++--------- 2 files changed, 287 insertions(+), 287 deletions(-) rename apps/BLEcontroller/{app-joy.js => app-ex2.js} (66%) diff --git a/apps/BLEcontroller/app-joy.js b/apps/BLEcontroller/app-ex2.js similarity index 66% rename from apps/BLEcontroller/app-joy.js rename to apps/BLEcontroller/app-ex2.js index 8da1aadcb..27e629d5d 100644 --- a/apps/BLEcontroller/app-joy.js +++ b/apps/BLEcontroller/app-ex2.js @@ -19,18 +19,18 @@ bottom_btn = false; msgNum = 0; // message number -NRF.setConnectionInterval(100); -Bangle.loadWidgets(); -Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_auto = {value: false}; -var status_chess = {value: false}; -var status_wake = {value: false}; +var status_spk = {value: true}; +var status_face = {value: true}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_hover = {value: false}; +var status_dome = {value: false}; /* trsnsmit message where @@ -69,49 +69,21 @@ Add an additional element to the icons array with a unique name and the data from the Image Object */ const icons = [ - { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" - }, - { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" - }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" }, { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" }, { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" }, { name: "sleep", @@ -122,12 +94,28 @@ const icons = [ data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" }, { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" }, { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" } ]; @@ -157,69 +145,79 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var joystickBtn = { +var happyBtn = { primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', + primary_text: 'Speak', + primary_icon: 'happy', }; -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { +var sadBtn = { primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', + primary_text: 'Speak', + primary_icon: 'sad', }; -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { +var speakBtn = { primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', + primary_text: 'Speak', + primary_icon: 'speak', }; -var chessBtn = { +var faceBtn = { primary_colour: 0xE9C7, primary_text: 'Off', - primary_icon: 'pawn', + primary_icon: 'facerecog', toggle: true, secondary_colour: 0x3F48, secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess + secondary_icon : 'facerecog', + value: status_face }; -var wakeBtn = { +var irisLightBtn = { primary_colour: 0xE9C7, - primary_text: 'Sleeping', + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', primary_icon: 'sleep', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Awake', + secondary_text: 'Open', secondary_icon : 'awake', - value: status_wake + value: status_iris }; -var autoBtn = { +var hoverBtn = { primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', + primary_text: 'Off', + primary_icon: 'hover', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover }; + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; + /* CONFIGURATION AREA - SCREEN DEFINITIONS a screen can have a button (as defined above) @@ -230,35 +228,32 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ + const menuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_h", + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, btn3: "back" }; -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", +const irisScreen = { + left: irisBtn, + right: irisLightBtn, btn3: "back" }; -const tailScreen = { - left: tailHBtn, - right: tailVBtn, +const lightsScreen = { + left: hoverBtn, + right: domeBtn, btn3: "back" }; -const chessScreen = { - left: chessBtn, - right: autoBtn, - btn3: "back" -}; - - /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -293,22 +288,28 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the appropiate status object is +For toggle buttons, the value of the sppropiate status object is inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ const Home = new State({ - state: "K9Menu", + state: "DalekMenu", screen: menuScreen, events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Lights; + } + if ((event.object == "middle") && (event.status == "end")) { + return Iris; + } if ((event.object == "right") && (event.status == "end")) { - return Joystick; + return Speak; } if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "wake", onOff(status_wake.value)); + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); return this; } transmit(this.state, event.object, event.status); @@ -316,31 +317,9 @@ const Home = new State({ } }); -const Chess = new State({ - state: "Chess", - screen: chessScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Tail = new State({ - state: "Tail", - screen: tailScreen, +const Speak = new State({ + state: "Speak", + screen: speakScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; @@ -350,18 +329,48 @@ const Tail = new State({ } }); -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, +const Iris = new State({ + state: "Iris", + screen: irisScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "servo", onOff(status_iris.value)); + return this; + } transmit(this.state, event.object, event.status); return this; - } + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } }); /* translate button status into english */ @@ -417,7 +426,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,28,119+x, 239); + g.fillRect(0+x,24,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 27e629d5d..8da1aadcb 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -19,18 +19,18 @@ bottom_btn = false; msgNum = 0; // message number +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); /* CONFIGURATION AREA - STATE VARIABLES declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_spk = {value: true}; -var status_face = {value: true}; -var status_iris_light = {value: false}; -var status_iris = {value: false}; -var status_hover = {value: false}; -var status_dome = {value: false}; +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; /* trsnsmit message where @@ -69,21 +69,49 @@ Add an additional element to the icons array with a unique name and the data from the Image Object */ const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" }, { - name: "spk_on", - data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" - }, - { - name: "spk_off", - data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" }, { - name: "facerecog", - data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" }, { name: "sleep", @@ -94,28 +122,12 @@ const icons = [ data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" }, { - name: "happy", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" }, { - name: "sad", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" - }, - { - name: "hover", - data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" - }, - { - name: "light", - data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" - }, - { - name: "speak", - data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" } ]; @@ -145,79 +157,69 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var happyBtn = { +var joystickBtn = { primary_colour: 0x653E, - primary_text: 'Speak', - primary_icon: 'happy', + primary_icon: 'joystick', + primary_text: 'Joystick', }; -var sadBtn = { +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'sad', + primary_text: 'Right', + primary_icon: 'right', }; -var speakBtn = { +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'speak', + primary_text: 'Wag Tail', + primary_icon: 'wag_v', }; -var faceBtn = { +var chessBtn = { primary_colour: 0xE9C7, primary_text: 'Off', - primary_icon: 'facerecog', + primary_icon: 'pawn', toggle: true, secondary_colour: 0x3F48, secondary_text: 'On', - secondary_icon : 'facerecog', - value: status_face + secondary_icon : 'pawn', + value: status_chess }; -var irisLightBtn = { +var wakeBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'light', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'light', - value: status_iris_light - }; - -var irisBtn = { - primary_colour: 0xE9C7, - primary_text: 'Closed', + primary_text: 'Sleeping', primary_icon: 'sleep', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Open', + secondary_text: 'Awake', secondary_icon : 'awake', - value: status_iris + value: status_wake }; -var hoverBtn = { +var autoBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'hover', + primary_text: 'Stop', + primary_icon: 'sit', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'hover', - value: status_hover + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto }; - var domeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'dalek', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'dalek', - value: status_dome - }; - /* CONFIGURATION AREA - SCREEN DEFINITIONS a screen can have a button (as defined above) @@ -228,32 +230,35 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ - const menuScreen = { - left: faceBtn, - right: speakBtn, - btn1: "hover", - btn2: "light", -}; - -const speakScreen = { - left: happyBtn, - right: sadBtn, + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_h", btn3: "back" }; -const irisScreen = { - left: irisBtn, - right: irisLightBtn, +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", btn3: "back" }; -const lightsScreen = { - left: hoverBtn, - right: domeBtn, +const tailScreen = { + left: tailHBtn, + right: tailVBtn, btn3: "back" }; +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -288,28 +293,22 @@ one, then the state machine will change to that new State and redrsw the screen appropriately. To add in additional capabilities for button presses, simply add an additional 'if' statement. -For toggle buttons, the value of the sppropiate status object is +For toggle buttons, the value of the appropiate status object is inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ const Home = new State({ - state: "DalekMenu", + state: "K9Menu", screen: menuScreen, events: (event) => { - if ((event.object == "top") && (event.status == "end")) { - return Lights; - } - if ((event.object == "middle") && (event.status == "end")) { - return Iris; - } if ((event.object == "right") && (event.status == "end")) { - return Speak; + return Joystick; } if ((event.object == "left") && (event.status == "end")) { - status_face.value = !status_face.value; - transmit(this.state, "face", onOff(status_face.value)); + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); return this; } transmit(this.state, event.object, event.status); @@ -317,9 +316,31 @@ const Home = new State({ } }); -const Speak = new State({ - state: "Speak", - screen: speakScreen, +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; @@ -329,48 +350,18 @@ const Speak = new State({ } }); -const Iris = new State({ - state: "Iris", - screen: irisScreen, +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_iris_light.value = !status_iris_light.value; - transmit(this.state, "light", onOff(status_iris_light.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_iris.value = !status_iris.value; - transmit(this.state, "servo", onOff(status_iris.value)); - return this; - } + transmit("Joystick", "joystick", "off"); + return Home; + } transmit(this.state, event.object, event.status); return this; - } -}); - -const Lights = new State({ - state: "Lights", - screen: lightsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_dome.value = !status_dome.value; - transmit(this.state, "dome", onOff(status_dome.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_hover.value = !status_hover.value; - transmit(this.state, "hover", onOff(status_hover.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } + } }); /* translate button status into english */ @@ -426,7 +417,7 @@ const drawButton = (params,side) => { text = params.secondary_text; icon = drawIcon(params.secondary_icon); } - g.fillRect(0+x,24,119+x, 239); + g.fillRect(0+x,28,119+x, 239); g.setColor(0x000); g.setFont("Vector",15); g.setFontAlign(0,0.0); From 39fc56f0b060384952750d4b38ebd7bbedd95931 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 20:16:26 +0100 Subject: [PATCH 44/72] Enabling navigation to sub-screens --- apps/BLEcontroller/app.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 8da1aadcb..0735aeee6 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -234,8 +234,7 @@ const menuScreen = { left: wakeBtn, right: joystickBtn, btn1: "pawn", - btn2: "wag_h", - btn3: "back" + btn2: "wag_v", }; const joystickScreen = { @@ -303,6 +302,12 @@ const Home = new State({ state: "K9Menu", screen: menuScreen, events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Chess; + } + if ((event.object == "middle") && (event.status == "end")) { + return Tail; + } if ((event.object == "right") && (event.status == "end")) { return Joystick; } From 65e5a2a5443cfe5931add37c0226c1ba57960edd Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 20:34:04 +0100 Subject: [PATCH 45/72] Final changes before pull request --- apps/BLEcontroller/Bangle.code-workspace | 7 - .../{app.js.old.js => app-joy.js} | 256 ++++++++++++------ apps/BLEcontroller/app.js | 232 ++++++---------- apps/BLEcontroller/video.png | Bin 178721 -> 0 bytes 4 files changed, 244 insertions(+), 251 deletions(-) delete mode 100644 apps/BLEcontroller/Bangle.code-workspace rename apps/BLEcontroller/{app.js.old.js => app-joy.js} (66%) delete mode 100644 apps/BLEcontroller/video.png diff --git a/apps/BLEcontroller/Bangle.code-workspace b/apps/BLEcontroller/Bangle.code-workspace deleted file mode 100644 index 90587e88f..000000000 --- a/apps/BLEcontroller/Bangle.code-workspace +++ /dev/null @@ -1,7 +0,0 @@ -{ - "folders": [ - { - "path": "/Users/hopkira/Documents/BangleApps" - } - ] -} \ No newline at end of file diff --git a/apps/BLEcontroller/app.js.old.js b/apps/BLEcontroller/app-joy.js similarity index 66% rename from apps/BLEcontroller/app.js.old.js rename to apps/BLEcontroller/app-joy.js index c8217988c..0735aeee6 100644 --- a/apps/BLEcontroller/app.js.old.js +++ b/apps/BLEcontroller/app-joy.js @@ -28,10 +28,9 @@ declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_printer = {value: false}; -var status_tv = {value: false}; -var status_light_hall = {value: false}; -var status_light_study = {value: false}; +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; /* trsnsmit message where @@ -71,16 +70,64 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "switch", - data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" }, { - name: "light", - data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" } ]; @@ -110,61 +157,68 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var lightBtn = { +var joystickBtn = { primary_colour: 0x653E, - primary_text: 'Lights', - primary_icon: 'light', + primary_icon: 'joystick', + primary_text: 'Joystick', }; -var socketsBtn = { +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { primary_colour: 0x33F9, - primary_text: 'Sockets', - primary_icon: 'switch', + primary_text: 'Right', + primary_icon: 'right', }; -var lightHallBtn = { - primary_colour: 0xE9C7, - primary_text: 'Hall Off', - primary_icon: 'light', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Hall On', - secondary_icon : 'light', - value: status_light_hall +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', }; -var lightStudyBtn = { - primary_colour: 0xE9C7, - primary_text: 'Study Off', - primary_icon: 'light', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Study On', - secondary_icon : 'light', - value: status_light_study -}; - -var socketTVBtn = { - primary_colour: 0xE9C7, - primary_text: 'TV Off', - primary_icon: 'switch', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'TV On', - secondary_icon : 'switch', - value: status_tv +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', }; -var socketPrinterBtn = { +var chessBtn = { primary_colour: 0xE9C7, - primary_text: 'Printer Off', - primary_icon: 'switch', + primary_text: 'Off', + primary_icon: 'pawn', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Printer On', - secondary_icon : 'switch', - value: status_printer -}; + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -176,23 +230,34 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ -const homeScreen = { - left: lightBtn, - right: socketsBtn, +const menuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_v", }; -const lightsScreen = { - left: lightHallBtn, - right: lightStudyBtn, +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", btn3: "back" }; -const socketsScreen = { - left: socketTVBtn, - right: socketPrinterBtn, +const tailScreen = { + left: tailHBtn, + right: tailVBtn, btn3: "back" }; +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -232,36 +297,23 @@ inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ + const Home = new State({ - state: "Home", - screen: homeScreen, + state: "K9Menu", + screen: menuScreen, events: (event) => { - if ((event.object == "right") && (event.status == "end")) { - return SocketsMenu; + if ((event.object == "top") && (event.status == "end")) { + return Chess; } - if ((event.object == "left") && (event.status == "end")) { - return LightsMenu; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const LightsMenu = new State({ - state: "LightsMenu", - screen: lightsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; + if ((event.object == "middle") && (event.status == "end")) { + return Tail; } if ((event.object == "right") && (event.status == "end")) { - status_light_study.value = !status_light_study.value; - transmit(this.state, "study", onOff(status_light_study.value)); - return this; + return Joystick; } if ((event.object == "left") && (event.status == "end")) { - status_light_hall.value = !status_light_hall.value; - transmit(this.state, "hall", onOff(status_light_hall.value)); + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); return this; } transmit(this.state, event.object, event.status); @@ -269,21 +321,21 @@ const LightsMenu = new State({ } }); -const SocketsMenu = new State({ - state: "SocketsMenu", - screen: socketsScreen, +const Chess = new State({ + state: "Chess", + screen: chessScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } if ((event.object == "right") && (event.status == "end")) { - status_printer.value = !status_printer.value; - transmit(this.state, "printer", onOff(status_printer.value)); + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_tv.value = !status_tv.value; - transmit(this.state, "tv", onOff(status_tv.value)); + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); return this; } transmit(this.state, event.object, event.status); @@ -291,6 +343,32 @@ const SocketsMenu = new State({ } }); +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + /* translate button status into english */ const startEnd = status => status ? "start" : "end"; diff --git a/apps/BLEcontroller/app.js b/apps/BLEcontroller/app.js index 0735aeee6..c8217988c 100644 --- a/apps/BLEcontroller/app.js +++ b/apps/BLEcontroller/app.js @@ -28,9 +28,10 @@ declare global variables for the toggle button statuses; if you add an additional toggle button you should declare it and initiase it here */ -var status_auto = {value: false}; -var status_chess = {value: false}; -var status_wake = {value: false}; +var status_printer = {value: false}; +var status_tv = {value: false}; +var status_light_hall = {value: false}; +var status_light_study = {value: false}; /* trsnsmit message where @@ -70,64 +71,16 @@ with a unique name and the data from the Image Object */ const icons = [ { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + name: "switch", + data: "gEBAP4B/AP4B/AP4B/AMgA3HPJdlVvI7/Hf47/Hf47/Hf47/Hf47/Hf4AvIPKRXAP4B/AP4B/AP4B/AJgA==" }, { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" }, { name: "back", data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" - }, - { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" - }, - { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" } ]; @@ -157,68 +110,61 @@ the program and it may be adviable to use the 'status_name' format to ensure it is clear. */ -var joystickBtn = { +var lightBtn = { primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', + primary_text: 'Lights', + primary_icon: 'light', }; -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { +var socketsBtn = { primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', + primary_text: 'Sockets', + primary_icon: 'switch', }; -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { - primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', - }; - -var chessBtn = { +var lightHallBtn = { primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'pawn', + primary_text: 'Hall Off', + primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess + secondary_text: 'Hall On', + secondary_icon : 'light', + value: status_light_hall }; -var wakeBtn = { +var lightStudyBtn = { primary_colour: 0xE9C7, - primary_text: 'Sleeping', - primary_icon: 'sleep', + primary_text: 'Study Off', + primary_icon: 'light', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Awake', - secondary_icon : 'awake', - value: status_wake + secondary_text: 'Study On', + secondary_icon : 'light', + value: status_light_study +}; + +var socketTVBtn = { + primary_colour: 0xE9C7, + primary_text: 'TV Off', + primary_icon: 'switch', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'TV On', + secondary_icon : 'switch', + value: status_tv }; -var autoBtn = { +var socketPrinterBtn = { primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', + primary_text: 'Printer Off', + primary_icon: 'switch', toggle: true, secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto - }; + secondary_text: 'Printer On', + secondary_icon : 'switch', + value: status_printer +}; /* CONFIGURATION AREA - SCREEN DEFINITIONS @@ -230,34 +176,23 @@ the left hand side of the screen. These are defined as btn1, bt2 and bt3. The values are names from the icon array. */ -const menuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_v", +const homeScreen = { + left: lightBtn, + right: socketsBtn, }; -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", +const lightsScreen = { + left: lightHallBtn, + right: lightStudyBtn, btn3: "back" }; -const tailScreen = { - left: tailHBtn, - right: tailVBtn, +const socketsScreen = { + left: socketTVBtn, + right: socketPrinterBtn, btn3: "back" }; -const chessScreen = { - left: chessBtn, - right: autoBtn, - btn3: "back" -}; - - /* base state definition Each of the screens correspond to a state; this class provides a constuctor for each @@ -297,45 +232,36 @@ inversed and the new value transmitted. */ /* The Home State/Page is where the application beings */ - const Home = new State({ - state: "K9Menu", - screen: menuScreen, + state: "Home", + screen: homeScreen, events: (event) => { - if ((event.object == "top") && (event.status == "end")) { - return Chess; - } - if ((event.object == "middle") && (event.status == "end")) { - return Tail; - } if ((event.object == "right") && (event.status == "end")) { - return Joystick; + return SocketsMenu; } if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "wake", onOff(status_wake.value)); - return this; + return LightsMenu; } transmit(this.state, event.object, event.status); return this; } }); -const Chess = new State({ - state: "Chess", - screen: chessScreen, +const LightsMenu = new State({ + state: "LightsMenu", + screen: lightsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); + status_light_study.value = !status_light_study.value; + transmit(this.state, "study", onOff(status_light_study.value)); return this; } if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); + status_light_hall.value = !status_light_hall.value; + transmit(this.state, "hall", onOff(status_light_hall.value)); return this; } transmit(this.state, event.object, event.status); @@ -343,32 +269,28 @@ const Chess = new State({ } }); -const Tail = new State({ - state: "Tail", - screen: tailScreen, +const SocketsMenu = new State({ + state: "SocketsMenu", + screen: socketsScreen, events: (event) => { if ((event.object == "bottom") && (event.status == "end")) { return Home; } + if ((event.object == "right") && (event.status == "end")) { + status_printer.value = !status_printer.value; + transmit(this.state, "printer", onOff(status_printer.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_tv.value = !status_tv.value; + transmit(this.state, "tv", onOff(status_tv.value)); + return this; + } transmit(this.state, event.object, event.status); return this; } }); -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - /* translate button status into english */ const startEnd = status => status ? "start" : "end"; diff --git a/apps/BLEcontroller/video.png b/apps/BLEcontroller/video.png deleted file mode 100644 index bd25e26a240e53ad6b09e0ba5eb1ab950f966d2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178721 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�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 Date: Mon, 1 Jun 2020 21:35:43 +0100 Subject: [PATCH 46/72] Added K9 controller --- apps.json | 14 ++ apps/k9control/README.md | 50 ++++ apps/k9control/app-icon.js | 1 + apps/k9control/app.js | 446 ++++++++++++++++++++++++++++++++++ apps/k9control/k9_icon_30.png | Bin 0 -> 4779 bytes 5 files changed, 511 insertions(+) create mode 100644 apps/k9control/README.md create mode 100644 apps/k9control/app-icon.js create mode 100644 apps/k9control/app.js create mode 100644 apps/k9control/k9_icon_30.png diff --git a/apps.json b/apps.json index bdc831069..56025ac3d 100644 --- a/apps.json +++ b/apps.json @@ -1785,6 +1785,20 @@ { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } ] }, + { "id": "k9control", + "name": "K9 BLE Controller with Joystick", + "shortName": "K9 Controller", + "icon": "k9_icon_30.png", + "version": "0.01", + "description": "My private K9 BLE controller", + "tags": "tool,bluetooth", + "readme": "README.md", + "allow_emulator":false, + "storage": [ + { "name": "k9control.app.js", "url": "app.js" }, + { "name": "k9control.img", "url": "app-icon.js", "evaluate": true } + ] + }, { "id": "widviz", "name": "Widget Visibility Widget", "shortName":"Viz Widget", diff --git a/apps/k9control/README.md b/apps/k9control/README.md new file mode 100644 index 000000000..6ce68efb3 --- /dev/null +++ b/apps/k9control/README.md @@ -0,0 +1,50 @@ +# K9 BLE Controller with Joystick + +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. + +Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + + + +To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: +* message number (up to the least significant four digits) +* screen name (up to four characters) +* object name (up to four characters) +* value/status (up to four characters) + +The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. + +Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) +/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# + +## Usage + +The application can be configured at will by changing the definitions of the screens, events, icons and buttons. + +Most changes are possible via data, rather than code change. + +## Features + +The default package contains three configurations: +* a simple home light and sockets controller UI (app.js) +* a robot controller UI with joystick (app-joy.js) +* a simple static assistant controller (app-ex2.js) + +You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. + +I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. + +## Controls + +The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. + +I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) + +## Requests + +In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) + +## Creator + +Richard Hopkins, FIET CEng +May 2020 diff --git a/apps/k9control/app-icon.js b/apps/k9control/app-icon.js new file mode 100644 index 000000000..55d7fb3cc --- /dev/null +++ b/apps/k9control/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("JyeEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAACIiIiAAAAAAAAAAAAAAAAAAAAACIiIgAAAAIAAAAAAAAAAAAAAAAiIiIiIAAAAiAAAAAAAAAAAAAAAiIiIiIAAAACIiAAAAAAAAAAAAAiIiIiIAAAAAAiIgAAAiIiIiIgAiIiIiIiAAAAAAIiIiIiIiIiIiIiIiIiIiIAAAAAACIiIiIiIiIiIiIiIiIiIgAAAAAAIiIiIiIiIiIiIiIiIiIiAAAAAAIiIiIiIiIiIiIgAiIiIgAAAAACIiIiIiIiIiIiIAACIiIAAAAAAiIiIiIiIiIiIiAAAAAAAAAAAAIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAAiIiIiIiIiIiIiIiAAAAAAAAAAAiIiIiIiIiIiIiIiIAAAAAAAAAAiIiIiIiIiIiIiIiIAAAAAAAAAIiIiIiIiIiIiIiIiIAAAAAAAAAIiIiIiIiIiIiIiIiIgAAAAAAACIiIiIiIiIiIiIiIiIgAAAAAAACIiIiIiIiIiIiIiIiIiAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) diff --git a/apps/k9control/app.js b/apps/k9control/app.js new file mode 100644 index 000000000..0735aeee6 --- /dev/null +++ b/apps/k9control/app.js @@ -0,0 +1,446 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +NRF.setConnectionInterval(100); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_auto = {value: false}; +var status_chess = {value: false}; +var status_wake = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0,4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "walk", + data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" + }, + { + name: "sit", + data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" + }, + { + name: "joystick", + data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" + }, + { + name: "left", + data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" + }, + { + name: "right", + data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" + }, + { + name: "forward", + data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" + }, + { + name: "backward", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" + }, + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "mic_on", + data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" + }, + { + name: "comms", + data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" + }, + { + name: "pawn", + data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "wag_h", + data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" + }, + { + name: "wag_v", + data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var joystickBtn = { + primary_colour: 0x653E, + primary_icon: 'joystick', + primary_text: 'Joystick', + }; + +var turnLeftBtn = { + primary_colour: 0x653E, + primary_text: 'Left', + primary_icon: 'left', + }; + +var turnRightBtn = { + primary_colour: 0x33F9, + primary_text: 'Right', + primary_icon: 'right', + }; + +var tailHBtn = { + primary_colour: 0x653E, + primary_text: 'Wag Tail', + primary_icon: 'wag_h', + }; + +var tailVBtn = { + primary_colour: 0x33F9, + primary_text: 'Wag Tail', + primary_icon: 'wag_v', + }; + +var chessBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'pawn', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'pawn', + value: status_chess + }; + +var wakeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Sleeping', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Awake', + secondary_icon : 'awake', + value: status_wake + }; + +var autoBtn = { + primary_colour: 0xE9C7, + primary_text: 'Stop', + primary_icon: 'sit', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Move', + secondary_icon : 'walk', + value: status_auto + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ +const menuScreen = { + left: wakeBtn, + right: joystickBtn, + btn1: "pawn", + btn2: "wag_v", +}; + +const joystickScreen = { + left: turnLeftBtn, + right: turnRightBtn, + btn1: "forward", + btn2: "backward", + btn3: "back" +}; + +const tailScreen = { + left: tailHBtn, + right: tailVBtn, + btn3: "back" +}; + +const chessScreen = { + left: chessBtn, + right: autoBtn, + btn3: "back" +}; + + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the appropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ + +const Home = new State({ + state: "K9Menu", + screen: menuScreen, + events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Chess; + } + if ((event.object == "middle") && (event.status == "end")) { + return Tail; + } + if ((event.object == "right") && (event.status == "end")) { + return Joystick; + } + if ((event.object == "left") && (event.status == "end")) { + status_wake.value = !status_wake.value; + transmit(this.state, "wake", onOff(status_wake.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Chess = new State({ + state: "Chess", + screen: chessScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_auto.value = !status_auto.value; + transmit(this.state, "follow", onOff(status_auto.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_chess.value = !status_chess.value; + transmit(this.state, "chess", onOff(status_chess.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Tail = new State({ + state: "Tail", + screen: tailScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* Joystick page state */ +const Joystick = new State({ + state: "Joystick", + screen: joystickScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + transmit("Joystick", "joystick", "off"); + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,28,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/k9control/k9_icon_30.png b/apps/k9control/k9_icon_30.png new file mode 100644 index 0000000000000000000000000000000000000000..f8ecae2b85dc24a11aaa4cb4e0dedba20c92e5cd GIT binary patch literal 4779 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 Z9FxZ=hg`FO|9t`gll|tDyZT2@{R^8<=kNdk literal 0 HcmV?d00001 From 3210548600a749a0847d8fe84ff91f5384ee6ee8 Mon Sep 17 00:00:00 2001 From: hopkira Date: Mon, 1 Jun 2020 21:44:00 +0100 Subject: [PATCH 47/72] Dedicated Dalek Control App --- apps.json | 42 ++- apps/dalekcontrol/README.md | 50 ++++ apps/dalekcontrol/app-icon.js | 1 + apps/dalekcontrol/app.js | 450 ++++++++++++++++++++++++++++ apps/dalekcontrol/dalek_icon_30.png | Bin 0 -> 7042 bytes 5 files changed, 529 insertions(+), 14 deletions(-) create mode 100644 apps/dalekcontrol/README.md create mode 100644 apps/dalekcontrol/app-icon.js create mode 100644 apps/dalekcontrol/app.js create mode 100644 apps/dalekcontrol/dalek_icon_30.png diff --git a/apps.json b/apps.json index 56025ac3d..e5209f601 100644 --- a/apps.json +++ b/apps.json @@ -1785,20 +1785,34 @@ { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } ] }, - { "id": "k9control", - "name": "K9 BLE Controller with Joystick", - "shortName": "K9 Controller", - "icon": "k9_icon_30.png", - "version": "0.01", - "description": "My private K9 BLE controller", - "tags": "tool,bluetooth", - "readme": "README.md", - "allow_emulator":false, - "storage": [ - { "name": "k9control.app.js", "url": "app.js" }, - { "name": "k9control.img", "url": "app-icon.js", "evaluate": true } - ] - }, + { "id": "k9control", + "name": "K9 BLE Controller with Joystick", + "shortName": "K9 Controller", + "icon": "k9_icon_30.png", + "version": "0.01", + "description": "My private K9 BLE controller", + "tags": "tool,bluetooth", + "readme": "README.md", + "allow_emulator":false, + "storage": [ + { "name": "k9control.app.js", "url": "app.js" }, + { "name": "k9control.img", "url": "app-icon.js", "evaluate": true } + ] + }, + { "id": "dalekcontrol", + "name": "Dalek BLE Controller with Joystick", + "shortName": "Dalek Controller", + "icon": "dalek_icon_30.png", + "version": "0.01", + "description": "My private Dalek BLE controller", + "tags": "tool,bluetooth", + "readme": "README.md", + "allow_emulator":false, + "storage": [ + { "name": "dalekcontrol.app.js", "url": "app.js" }, + { "name": "dalekcontrol.img", "url": "app-icon.js", "evaluate": true } + ] + }, { "id": "widviz", "name": "Widget Visibility Widget", "shortName":"Viz Widget", diff --git a/apps/dalekcontrol/README.md b/apps/dalekcontrol/README.md new file mode 100644 index 000000000..3ffe7f514 --- /dev/null +++ b/apps/dalekcontrol/README.md @@ -0,0 +1,50 @@ +# Dalek Controller + +A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. + +Amaze your friends by controlling your robot, your house or any other BLE device from your watch! + + + +To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: +* message number (up to the least significant four digits) +* screen name (up to four characters) +* object name (up to four characters) +* value/status (up to four characters) + +The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. + +Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) +/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# + +## Usage + +The application can be configured at will by changing the definitions of the screens, events, icons and buttons. + +Most changes are possible via data, rather than code change. + +## Features + +The default package contains three configurations: +* a simple home light and sockets controller UI (app.js) +* a robot controller UI with joystick (app-joy.js) +* a simple static assistant controller (app-ex2.js) + +You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. + +I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. + +## Controls + +The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. + +I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) + +## Requests + +In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) + +## Creator + +Richard Hopkins, FIET CEng +May 2020 diff --git a/apps/dalekcontrol/app-icon.js b/apps/dalekcontrol/app-icon.js new file mode 100644 index 000000000..b228e290b --- /dev/null +++ b/apps/dalekcontrol/app-icon.js @@ -0,0 +1 @@ +E.toArrayBuffer(atob("Hh6EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIAAAAAAAAAAAAAAAACIiIiIAAAAAAAACIgAAIiICICIiAAAiIAACIiAiIiAgAgIiIgIiIAAAIgIiIiAAACIiIiAiAAAAAiIiIiAAACIiIiIgAAAAACIiIiAgAAIiIiIAAAAAAiIiIiICIgIiIiIgAAAAAiIiIiIgAiIiIiIgAAAAAiIiIiIiIiIiIiIgAAAAAiACIAAAAAACIAIgAAAAAgAAIAAAAAAAIAAgAAAAIiIiIiIiIiIiIiIiAAAAIiIiIiIiIiIiIiIiAAAAAAAAIAAAAAAAIAAAAAAAIAAAIAAAAAAAIAACAAAAIAAAIAAAAAAAIAACAAACIiIiIiIiIiIiIiIiIAACIAACIAAAAAACIAACIAAAIAAAIAAAAAAAIAACAAACIAACIAAAAAACIAACIAAiIiIiIiIiIiIiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) diff --git a/apps/dalekcontrol/app.js b/apps/dalekcontrol/app.js new file mode 100644 index 000000000..27e629d5d --- /dev/null +++ b/apps/dalekcontrol/app.js @@ -0,0 +1,450 @@ +/* +========================================================== +Simple event based robot controller that enables robot +to switch into automatic or manual control modes. Behaviours +are controlled via a simple finite state machine. +In automatic mode the +robot will look after itself. In manual mode, the watch +will provide simple forward, back, left and right commands. +The messages will be transmitted to a partner BLE Espruino +using BLE +Written by Richard Hopkins, May 2020 +========================================================== +declare global variables for watch button statuses */ +top_btn = false; +middle_btn = false; +left_btn= false; // the left side of the touch screen +right_btn = false; // the right side of the touch screen +bottom_btn = false; + +msgNum = 0; // message number + +/* +CONFIGURATION AREA - STATE VARIABLES +declare global variables for the toggle button +statuses; if you add an additional toggle button +you should declare it and initiase it here */ + +var status_spk = {value: true}; +var status_face = {value: true}; +var status_iris_light = {value: false}; +var status_iris = {value: false}; +var status_hover = {value: false}; +var status_dome = {value: false}; + +/* trsnsmit message +where +s = first character of state, +o = first three character of object name +v = value of state.object +*/ + +const transmit = (state,object,status) => { + msgNum ++; + msg = { + n: msgNum.toString().slice(-4), + s: state.substr(0,4), + o: object.substr(0,4), + v: status.substr(0,4), + }; + message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; + NRF.setAdvertising({},{ + showName: false, + manufacturer: 0x0590, + manufacturerData: JSON.stringify(message)}); +}; + +/* +CONFIGURATION AREA - ICON DEFINITIONS +Retrieve 30px PNG icons from: +https://icons8.com/icon/set/speak/ios-glyphs +Create icons using: +https://www.espruino.com/Image+Converter +Use compression: true +Transparency: true +Diffusion: flat +Colours: 16bit RGB +Ouput as: Image Object +Add an additional element to the icons array +with a unique name and the data from the Image Object +*/ +const icons = [ + { + name: "back", + data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" + }, + { + name: "spk_on", + data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" + }, + { + name: "spk_off", + data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" + }, + { + name: "facerecog", + data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" + }, + { + name: "sleep", + data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" + }, + { + name: "awake", + data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" + }, + { + name: "happy", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" + }, + { + name: "sad", + data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" + }, + { + name: "hover", + data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" + }, + { + name: "light", + data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" + }, + { + name: "speak", + data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" + }, + { + name: "dalek", + data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" + } + ]; + +/* finds icon data by name in the icon array and returns an image object*/ +const drawIcon = (name) => { + for (var icon of icons) { + if (icon.name == name) { + image = { + width : 30, height : 30, bpp : 16, + transparent : 1, + buffer: require("heatshrink").decompress(atob(icon.data)) + }; + return image;} + } +}; + +/* +CONFIGURATION AREA - BUTTON DEFINITIONS +for a simple button, just define a primary colour +and an icon name from the icon array and +the text to display beneath the button +for toggle buttons, additionally provide secondary +colours, icon name and text. Also provide a reference +to a global variable for the value of the button. +The global variable should be declared at the start of +the program and it may be adviable to use the 'status_name' +format to ensure it is clear. +*/ + +var happyBtn = { + primary_colour: 0x653E, + primary_text: 'Speak', + primary_icon: 'happy', + }; + +var sadBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'sad', + }; + +var speakBtn = { + primary_colour: 0x33F9, + primary_text: 'Speak', + primary_icon: 'speak', + }; + +var faceBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'facerecog', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'facerecog', + value: status_face + }; + +var irisLightBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'light', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'light', + value: status_iris_light + }; + +var irisBtn = { + primary_colour: 0xE9C7, + primary_text: 'Closed', + primary_icon: 'sleep', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'Open', + secondary_icon : 'awake', + value: status_iris + }; + +var hoverBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'hover', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'hover', + value: status_hover + }; + + var domeBtn = { + primary_colour: 0xE9C7, + primary_text: 'Off', + primary_icon: 'dalek', + toggle: true, + secondary_colour: 0x3F48, + secondary_text: 'On', + secondary_icon : 'dalek', + value: status_dome + }; + +/* +CONFIGURATION AREA - SCREEN DEFINITIONS +a screen can have a button (as defined above) +on the left and/or the right of the screen. +in adddition a screen can optionally have +an icon for each of the three buttons on +the left hand side of the screen. These +are defined as btn1, bt2 and bt3. The +values are names from the icon array. +*/ + +const menuScreen = { + left: faceBtn, + right: speakBtn, + btn1: "hover", + btn2: "light", +}; + +const speakScreen = { + left: happyBtn, + right: sadBtn, + btn3: "back" +}; + +const irisScreen = { + left: irisBtn, + right: irisLightBtn, + btn3: "back" +}; + +const lightsScreen = { + left: hoverBtn, + right: domeBtn, + btn3: "back" +}; + +/* base state definition +Each of the screens correspond to a state; +this class provides a constuctor for each +of the states +*/ +class State { + constructor(params) { + this.state = params.state; + this.events = params.events; + this.screen = params.screen; + } +} + +/* +CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS +This area defines how each screen behaves. +Each screen corresponds to a different State of the +state machine. This makes it much easier to isolate +behaviours between screens. +The state value is transmitted whenever a button is pressed +to provide context (so the receiving device, knows which +button was pressed on which screen). +The screens are defined above. +The events section identifies if a particular button has been +pressed and released on the screen and an action can then be taken. +The events function receives a notification from a mySetWatch which +provides an event object that identifies which button and whether +it has been pressed down or released. Actions can then be taken. +The events function will always return a State object. +If the events function returns different State from the current +one, then the state machine will change to that new State and redrsw +the screen appropriately. +To add in additional capabilities for button presses, simply add +an additional 'if' statement. +For toggle buttons, the value of the sppropiate status object is +inversed and the new value transmitted. +*/ + +/* The Home State/Page is where the application beings */ + +const Home = new State({ + state: "DalekMenu", + screen: menuScreen, + events: (event) => { + if ((event.object == "top") && (event.status == "end")) { + return Lights; + } + if ((event.object == "middle") && (event.status == "end")) { + return Iris; + } + if ((event.object == "right") && (event.status == "end")) { + return Speak; + } + if ((event.object == "left") && (event.status == "end")) { + status_face.value = !status_face.value; + transmit(this.state, "face", onOff(status_face.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Speak = new State({ + state: "Speak", + screen: speakScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Iris = new State({ + state: "Iris", + screen: irisScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_iris_light.value = !status_iris_light.value; + transmit(this.state, "light", onOff(status_iris_light.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_iris.value = !status_iris.value; + transmit(this.state, "servo", onOff(status_iris.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +const Lights = new State({ + state: "Lights", + screen: lightsScreen, + events: (event) => { + if ((event.object == "bottom") && (event.status == "end")) { + return Home; + } + if ((event.object == "right") && (event.status == "end")) { + status_dome.value = !status_dome.value; + transmit(this.state, "dome", onOff(status_dome.value)); + return this; + } + if ((event.object == "left") && (event.status == "end")) { + status_hover.value = !status_hover.value; + transmit(this.state, "hover", onOff(status_hover.value)); + return this; + } + transmit(this.state, event.object, event.status); + return this; + } +}); + +/* translate button status into english */ +const startEnd = status => status ? "start" : "end"; + +/* translate status into english */ +const onOff= status => status ? "on" : "off"; + + +/* create watching functions that will change the global +button status when pressed or released +This is actuslly the hesrt of the program. When a button +is not being pressed, nothing is happening (no loops). +This makes the progrsm more battery efficient. +When a setWatch event is raised, the custom callbacks defined +here will be called. These then fired as events to the current +state/screen of the state mschine. +Some events, will result in the stste of the state machine +chsnging, which is why the screen is redrswn after each +button press. +*/ +const setMyWatch = (params) => { + setWatch(() => { + params.bool=!params.bool; + machine = machine.events({object: params.label, status: startEnd(params.bool)}); + drawScreen(machine.screen); + }, params.btn, {repeat:true, edge:"both"}); +}; + +/* object array used to set up the watching functions +*/ +const buttons = [ + {bool : bottom_btn, label : "bottom",btn : BTN3}, + {bool : middle_btn, label : "middle",btn : BTN2}, + {bool : top_btn, label : "top",btn : BTN1}, + {bool : left_btn, label : "left",btn : BTN4}, + {bool : right_btn, label : "right",btn : BTN5} + ]; + +/* set up watchers for buttons */ +for (var button of buttons) + {setMyWatch(button);} + +/* Draw various kinds of buttons */ +const drawButton = (params,side) => { + g.setFontAlign(0,1); + icon = drawIcon(params.primary_icon); + text = params.primary_text; + g.setColor(params.primary_colour); + const x = (side == "left") ? 0 : 120; + if ((params.toggle) && (params.value.value)) { + g.setColor(params.secondary_colour); + text = params.secondary_text; + icon = drawIcon(params.secondary_icon); + } + g.fillRect(0+x,24,119+x, 239); + g.setColor(0x000); + g.setFont("Vector",15); + g.setFontAlign(0,0.0); + g.drawString(text,60+x,160); + options = {rotate: 0, scale:2}; + g.drawImage(icon,x+60,120,options); +}; + +/* Draw the pages corresponding to the states */ +const drawScreen = (params) => { + drawButton(params.left,'left'); + drawButton(params.right,'right'); + g.setColor(0x000); + if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} + if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} + if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} +}; + +machine = Home; // instantiate the state machine at Home +Bangle.drawWidgets(); // draw active widgets +drawScreen(machine.screen); // draw the screen diff --git a/apps/dalekcontrol/dalek_icon_30.png b/apps/dalekcontrol/dalek_icon_30.png new file mode 100644 index 0000000000000000000000000000000000000000..b59750e9d716d2f67290004367bb3a746f9e6f8d GIT binary patch literal 7042 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 Date: Mon, 8 Jun 2020 22:16:20 +0200 Subject: [PATCH 48/72] Improve rendering of Numeral 1, fix issue with alarms not showing up --- apps.json | 2 +- apps/numerals/ChangeLog | 1 + apps/numerals/numerals.app.js | 8 ++------ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps.json b/apps.json index 587771fdb..8ea3c837b 100644 --- a/apps.json +++ b/apps.json @@ -1332,7 +1332,7 @@ "name": "Numerals Clock", "shortName": "Numerals Clock", "icon": "numerals.png", - "version":"0.05", + "version":"0.06", "description": "A simple big numerals clock", "tags": "numerals,clock", "type":"clock", diff --git a/apps/numerals/ChangeLog b/apps/numerals/ChangeLog index 855442377..9e6abb393 100644 --- a/apps/numerals/ChangeLog +++ b/apps/numerals/ChangeLog @@ -3,3 +3,4 @@ 0.03: maximize numerals, make menu button configurable, change icon to mac palette, add default settings file, respect 12hour setting 0.04: Don't overwrite existing settings on app update 0.05: Fix settings issue +0.06: Improve rendering of Numeral 1, fix issue with alarms not showing up diff --git a/apps/numerals/numerals.app.js b/apps/numerals/numerals.app.js index a74da4460..37f8219c4 100644 --- a/apps/numerals/numerals.app.js +++ b/apps/numerals/numerals.app.js @@ -8,7 +8,7 @@ var numerals = { 0:[[9,1,82,1,90,9,90,92,82,100,9,100,1,92,1,9],[30,25,61,25,69,33,69,67,61,75,30,75,22,67,22,33]], - 1:[[59,1,82,1,90,9,90,92,82,100,73,100,65,92,65,27,59,27,51,19,51,9]], + 1:[[50,1,82,1,90,9,90,92,82,100,73,100,65,92,65,27,50,27,42,19,42,9]], 2:[[9,1,82,1,90,9,90,53,82,61,21,61,21,74,82,74,90,82,90,92,82,100,9,100,1,92,1,48,9,40,70,40,70,27,9,27,1,19,1,9]], 3:[[9,1,82,1,90,9,90,92,82,100,9,100,1,92,1,82,9,74,70,74,70,61,9,61,1,53,1,48,9,40,70,40,70,27,9,27,1,19,1,9]], 4:[[9,1,14,1,22,9,22,36,69,36,69,9,77,1,82,1,90,9,90,92,82,100,78,100,70,92,70,61,9,61,1,53,1,9]], @@ -70,12 +70,8 @@ function draw(drawMode){ } Bangle.setLCDMode(); - -clearWatch(); +g.reset().clear(); setWatch(Bangle.showLauncher, settings.menuButton, {repeat:false,edge:"falling"}); - -g.clear(); -clearInterval(); if (settings.color>0) _rCol=settings.color-1; interval=setInterval(draw, REFRESH_RATE, settings.drawMode); draw(settings.drawMode); From 2cb595300e4f76a8da24906356796aa699073718 Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Sat, 6 Jun 2020 22:26:46 -0400 Subject: [PATCH 49/72] weather: redraw last update time less frequently --- apps/weather/app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/weather/app.js b/apps/weather/app.js index b43a52517..ea8936886 100644 --- a/apps/weather/app.js +++ b/apps/weather/app.js @@ -3,7 +3,7 @@ function formatDuration(millis) { let pluralize = (n, w) => n + " " + w + (n == 1 ? "" : "s"); - if (millis < 60000) return pluralize(Math.floor(millis/1000), "second"); + if (millis < 60000) return "< 1 minute"; if (millis < 3600000) return pluralize(Math.floor(millis/60000), "minute"); if (millis < 86400000) return pluralize(Math.floor(millis/3600000), "hour"); return pluralize(Math.floor(millis/86400000), "day"); @@ -41,7 +41,7 @@ g.setFont("6x8", 1).setFontAlign(0, 0, 0); g.drawString(w.txt.charAt(0).toUpperCase()+w.txt.slice(1), 120, 190); - drawUpdateTime(w); + drawUpdateTime(); g.flip(); } @@ -63,7 +63,7 @@ } } - let interval = setInterval(drawUpdateTime, 1000); + let interval = setInterval(drawUpdateTime, 60000); Bangle.on('lcdPower', (on) => { if (interval) { clearInterval(interval); @@ -71,7 +71,7 @@ } if (on) { drawUpdateTime(); - interval = setInterval(drawUpdateTime, 1000); + interval = setInterval(drawUpdateTime, 60000); } }); From 60b4fc3351d0b57071bfd5fe9d55c71a5c56619f Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Sun, 7 Jun 2020 15:37:31 -0400 Subject: [PATCH 50/72] weather: make expiry default to 2 hours --- apps/weather/lib.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/weather/lib.js b/apps/weather/lib.js index 8eda2dea9..fffc523ca 100644 --- a/apps/weather/lib.js +++ b/apps/weather/lib.js @@ -6,8 +6,9 @@ function scheduleExpiry(json) { clearTimeout(expiryTimeout); expiryTimeout = undefined; } - if (json.weather && json.weather.time && json.expiry) { - let t = json.weather.time + json.expiry - Date.now(); + let expiry = "expiry" in json ? json.expiry : 2*3600000; + if (json.weather && json.weather.time && expiry) { + let t = json.weather.time + expiry - Date.now(); expiryTimeout = setTimeout(() => { expiryTimeout = undefined; From 19ce8b888e2cc3ec1fc15033f670b99a272b028d Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Mon, 8 Jun 2020 21:52:23 -0400 Subject: [PATCH 51/72] weather: bump version --- apps.json | 2 +- apps/weather/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 587771fdb..be83ef747 100644 --- a/apps.json +++ b/apps.json @@ -414,7 +414,7 @@ { "id": "weather", "name": "Weather", "icon": "icon.png", - "version":"0.02", + "version":"0.03", "description": "Show Gadgetbridge weather report", "readme": "readme.md", "tags": "widget,outdoors", diff --git a/apps/weather/ChangeLog b/apps/weather/ChangeLog index f0eae0198..5e27e1bf4 100644 --- a/apps/weather/ChangeLog +++ b/apps/weather/ChangeLog @@ -1 +1,2 @@ 0.02: Make minor adjustments to widget, and discard stale weather data after a configurable period. +0.03: Fix flickering last updated time. \ No newline at end of file From 99dcd7868c60c69a2bea11748419ad66d1092489 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 9 Jun 2020 09:23:55 +0100 Subject: [PATCH 52/72] Fix apploader node.js app issues - invalid length when uploading (base64 encode issues) and path (when run from directory other than the root) --- bin/apploader.js | 10 ++++++++-- js/appinfo.js | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/bin/apploader.js b/bin/apploader.js index a35778bae..616f3f3f7 100755 --- a/bin/apploader.js +++ b/bin/apploader.js @@ -78,8 +78,12 @@ function cmdListDevices() { }); noble.startScanning([], true); setTimeout(function() { + console.log("Stopping scan"); noble.stopScanning(); - }, 2000); + setTimeout(function() { + process.exit(0); + }, 500); + }, 4000); } function cmdInstallApp(appId, deviceAddress) { @@ -88,7 +92,8 @@ function cmdInstallApp(appId, deviceAddress) { if (app.custom) ERROR(`App ${JSON.stringify(appId)} requires HTML customisation`); return AppInfo.getFiles(app, { fileGetter:function(url) { - return Promise.resolve(require("fs").readFileSync(url).toString()); + console.log(__dirname+"/"+url); + return Promise.resolve(require("fs").readFileSync(__dirname+"/../"+url).toString()); }, settings : SETTINGS}).then(files => { //console.log(files); var command = files.map(f=>f.cmd).join("\n")+"\n"; @@ -101,6 +106,7 @@ function bangleSend(command, deviceAddress) { var args = [].slice.call(arguments); console.log("UART: "+args.join(" ")); } + //console.log("Sending",JSON.stringify(command)); var RESET = true; var DEVICEADDRESS = ""; diff --git a/js/appinfo.js b/js/appinfo.js index 6ed8310ad..54f403f91 100644 --- a/js/appinfo.js +++ b/js/appinfo.js @@ -1,8 +1,8 @@ if (typeof btoa==="undefined") { // Don't define btoa as a function here because Apple's // iOS browser defines the function even though it's in - // an IF statement that is never executed! - btoa = function(d) { return Buffer.from(d).toString('base64'); } + // an IF statement that is never executed + btoa = function(d) { return Buffer.from(d,'binary').toString('base64'); } } // Converts a string into most efficient way to send to Espruino (either json, base64, or compressed base64) From 3dc60b24a4c0d32a210f8c2988251c0dae36b58f Mon Sep 17 00:00:00 2001 From: jeffmer Date: Tue, 9 Jun 2020 12:06:55 +0100 Subject: [PATCH 53/72] Create README.md --- apps/magnav/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 apps/magnav/README.md diff --git a/apps/magnav/README.md b/apps/magnav/README.md new file mode 100644 index 000000000..421376db9 --- /dev/null +++ b/apps/magnav/README.md @@ -0,0 +1 @@ +dummy From 2ea54d5863cfe527f0516f0d78bf68a14a5888e9 Mon Sep 17 00:00:00 2001 From: jeffmer Date: Tue, 9 Jun 2020 12:08:14 +0100 Subject: [PATCH 54/72] Add files via upload --- apps/magnav/ChangeLog | 4 + apps/magnav/README.md | 27 ++++- apps/magnav/magnav-icon.js | 1 + apps/magnav/magnav.js | 220 +++++++++++++++++++++++++++++++++++++ apps/magnav/magnav.min.js | 10 ++ apps/magnav/magnav.png | Bin 0 -> 2354 bytes apps/magnav/screenshot.jpg | Bin 0 -> 72721 bytes 7 files changed, 261 insertions(+), 1 deletion(-) create mode 100644 apps/magnav/ChangeLog create mode 100644 apps/magnav/magnav-icon.js create mode 100644 apps/magnav/magnav.js create mode 100644 apps/magnav/magnav.min.js create mode 100644 apps/magnav/magnav.png create mode 100644 apps/magnav/screenshot.jpg diff --git a/apps/magnav/ChangeLog b/apps/magnav/ChangeLog new file mode 100644 index 000000000..6a33b0ce9 --- /dev/null +++ b/apps/magnav/ChangeLog @@ -0,0 +1,4 @@ +0.01: New App! +0.02: Course marker +0.03: Tilt compensation and calibration + diff --git a/apps/magnav/README.md b/apps/magnav/README.md index 421376db9..a036644fb 100644 --- a/apps/magnav/README.md +++ b/apps/magnav/README.md @@ -1 +1,26 @@ -dummy +# Navigation Compass + +This is a tilt and roll compensated compass with a linear display. The compass will display the same direction that it shows when flat as when it is tilted (rotation around the W-S axis) or rolled (rotation around the N-S) axis. *Even with compensation, it would be beyond foolish to rely solely on this app for any serious navigational purpose.* + +![](screenshot.jpg) + +## Calibration + +Correct operation of this app depends critically on calibration. When first run on a Bangle, the app will request calibration. This lasts for 30 seconds during which you should move the watch slowly through figures of 8. It is important that during calibration the watch is fully rotated around each of it axes. If the app does give the correct direction heading or is not stable with respect to tilt and roll - redo the calibration by pressing *BTN3*. Calibration data is recorded in a storage file named `magnav.json`. + +## Controls + +*BTN1* - switches to your selected clock app. + +*BTN2* - switches to the app launcher. + +*BTN3* - invokes calibration ( can be cancelled if pressed accidentally) + +*Touch Left* - marks the current heading with a blue circle - see screen shot. This can be used to take a bearing and then follow it. + +*Touch Right* - cancels the marker (blue circle not displayed). + + +## Support + +Please report bugs etc. by raising an issue [here](https://github.com/jeffmer/JeffsBangleAppsDev). \ No newline at end of file diff --git a/apps/magnav/magnav-icon.js b/apps/magnav/magnav-icon.js new file mode 100644 index 000000000..efdad48f9 --- /dev/null +++ b/apps/magnav/magnav-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwhC/ACMBiIACiAWQCoYADCyEimf/mczkQYOBwMj/4ABC4MzmQYMLYMvCwQXDDARjKFogXFDAQuJiQWEC4szkIwIIooXHGBAuHC4wwIFwXcp4XKGA8Rn//7vMAYIXImYXFIwc97nNDAQXHJAsBj4RB/owBDAQXHmIXERofz7vcDAQXHMApeCAAPdGAIYBC45gFUok9GAXM4hgIXpBgBGAQYIPAcBibTEC4IwC4fzPBIXGJAk/C5amCJAnM74VBVQwXKVIPMbAQXRMAIXEJAoXLnpdDC5Z3FMAPTB4LhCC6ApEC5bXEDAwwBDwjvDgAXHCQgwFC4kRKoQAFGAgXDiIXEl4XKSIkyC4ioHC4qsCOwh4KRYoFCkIXEMBIXEn5eGMBQXGLwpIKC4hGIGBIWFFw4wJFxwwCkYXJFxIwCJIoWFFxIwCGIgWEFxQYEkTRDkQWODAYAFCxxjDAARbLAH4AFA==")) diff --git a/apps/magnav/magnav.js b/apps/magnav/magnav.js new file mode 100644 index 000000000..111d42c38 --- /dev/null +++ b/apps/magnav/magnav.js @@ -0,0 +1,220 @@ + +const Yoff = 80; +var pal2color = new Uint16Array([0x0000,0xffff,0x07ff,0xC618],0,2); +var buf = Graphics.createArrayBuffer(240,50,2,{msb:true}); +Bangle.setLCDTimeout(30); + +function flip(b,y) { + g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer, palette:pal2color},0,y); + b.clear(); +} + +const labels = ["N","NE","E","SE","S","SW","W","NW"]; +var brg=null; + +function drawCompass(course) { + buf.setColor(1); + buf.setFont("Vector",16); + var start = course-90; + if (start<0) start+=360; + buf.fillRect(28,45,212,49); + var xpos = 30; + var frag = 15 - start%15; + if (frag<15) xpos+=frag; else frag = 0; + for (var i=frag;i<=180-frag;i+=15){ + var res = start + i; + if (res%90==0) { + buf.drawString(labels[Math.floor(res/45)%8],xpos-8,0); + buf.fillRect(xpos-2,25,xpos+2,45); + } else if (res%45==0) { + buf.drawString(labels[Math.floor(res/45)%8],xpos-12,0); + buf.fillRect(xpos-2,30,xpos+2,45); + } else if (res%15==0) { + buf.fillRect(xpos,35,xpos+1,45); + } + xpos+=15; + } + if (brg) { + var bpos = brg - course; + if (bpos>180) bpos -=360; + if (bpos<-180) bpos +=360; + bpos+=120; + if (bpos<30) bpos = 14; + if (bpos>210) bpos = 226; + buf.setColor(2); + buf.fillCircle(bpos,40,8); + } + flip(buf,Yoff); +} + +var heading = 0; +function newHeading(m,h){ + var s = Math.abs(m - h); + var delta = (m>h)?1:-1; + if (s>=180){s=360-s; delta = -delta;} + if (s<2) return h; + var hd = h + delta*(1 + Math.round(s/5)); + if (hd<0) hd+=360; + if (hd>360)hd-= 360; + return hd; +} + +var candraw = false; +var CALIBDATA = require("Storage").readJSON("magnav.json",1)||null; + +function tiltfixread(O,S){ + var start = Date.now(); + var m = Bangle.getCompass(); + var g = Bangle.getAccel(); + m.dx =(m.x-O.x)*S.x; m.dy=(m.y-O.y)*S.y; m.dz=(m.z-O.z)*S.z; + var d = Math.atan2(-m.dx,m.dy)*180/Math.PI; + if (d<0) d+=360; + var phi = Math.atan(-g.x/-g.z); + var cosphi = Math.cos(phi), sinphi = Math.sin(phi); + var theta = Math.atan(-g.y/(-g.x*sinphi-g.z*cosphi)); + var costheta = Math.cos(theta), sintheta = Math.sin(theta); + var xh = m.dy*costheta + m.dx*sinphi*sintheta + m.dz*cosphi*sintheta; + var yh = m.dz*sinphi - m.dx*cosphi; + var psi = Math.atan2(yh,xh)*180/Math.PI; + if (psi<0) psi+=360; + return psi; +} + +// Note actual mag is 360-m, error in firmware +function reading() { + var d = tiltfixread(CALIBDATA.offset,CALIBDATA.scale); + heading = newHeading(d,heading); + drawCompass(heading); + buf.setColor(1); + buf.setFont("6x8",2); + buf.setFontAlign(-1,-1); + buf.drawString("o",170,0); + buf.setFont("Vector",40); + var course = Math.round(heading); + var cs = course.toString(); + cs = course<10?"00"+cs : course<100 ?"0"+cs : cs; + buf.drawString(cs,70,10); + flip(buf,Yoff+80); +} + +function calibrate(){ + var max={x:-32000, y:-32000, z:-32000}, + min={x:32000, y:32000, z:32000}; + var ref = setInterval(()=>{ + var m = Bangle.getCompass(); + max.x = m.x>max.x?m.x:max.x; + max.y = m.y>max.y?m.y:max.y; + max.z = m.z>max.z?m.z:max.z; + min.x = m.x { + setTimeout(()=>{ + if(ref) clearInterval(ref); + var offset = {x:(max.x+min.x)/2,y:(max.y+min.y)/2,z:(max.z+min.z)/2}; + var delta = {x:(max.x-min.x)/2,y:(max.y-min.y)/2,z:(max.z-min.z)/2}; + var avg = (delta.x+delta.y+delta.z)/3; + var scale = {x:avg/delta.x, y:avg/delta.y, z:avg/delta.z}; + resolve({offset:offset,scale:scale}); + },30000); + }); +} + +function docalibrate(e,first){ + const title = "Calibrate"; + const msg = "takes 30 seconds"; + function action(b){ + if (b) { + buf.setColor(1); + buf.setFont("Vector",24); + buf.setFontAlign(0,-1); + buf.drawString("Fig 8s to",120,0); + buf.drawString("Calibrate",120,26); + flip(buf,Yoff); + calibrate().then((r)=>{ + require("Storage").write("magnav.json",r); + CALIBDATA = r; + startdraw(); + setButtons(); + }); + } else { + startdraw(); + setTimeout(setButtons,1000); + } + } + if (first===undefined) first=false; + stopdraw(); + clearWatch(); + if (first) + E.showAlert(msg,title).then(action.bind(null,true)); + else + E.showPrompt(msg,{title:title,buttons:{"Start":true,"Cancel":false}}).then(action); +} + +Bangle.on('touch', function(b) { + if(!candraw) return; + if(b==1) brg=heading; + if(b==2) brg=null; + }); + +var intervalRef; + +function startdraw(){ + g.clear(); + g.setColor(1,0.5,0.5); + g.fillPoly([120,Yoff+50,110,Yoff+70,130,Yoff+70]); + g.setColor(1,1,1); + Bangle.drawWidgets(); + candraw = true; + intervalRef = setInterval(reading,200); +} + +function stopdraw() { + candraw=false; + if(intervalRef) {clearInterval(intervalRef);} +} + +function setButtons(){ + setWatch(()=>{load();}, BTN1, {repeat:false,edge:"falling"}); + setWatch(Bangle.showLauncher, BTN2, {repeat:false,edge:"falling"}); + setWatch(docalibrate, BTN3, {repeat:false,edge:"falling"}); +} + +var SCREENACCESS = { + withApp:true, + request:function(){ + this.withApp=false; + stopdraw(); + clearWatch(); + }, + release:function(){ + this.withApp=true; + startdraw(); + setButtons(); + } +}; + +Bangle.on('lcdPower',function(on) { + if (!SCREENACCESS.withApp) return; + if (on) { + startdraw(); + } else { + stopdraw(); + } +}); + +Bangle.on('kill',()=>{Bangle.setCompassPower(0);}); + +Bangle.loadWidgets(); +Bangle.setCompassPower(1); +if (!CALIBDATA) + docalibrate({},true); +else { + startdraw(); + setButtons(); +} + + + + diff --git a/apps/magnav/magnav.min.js b/apps/magnav/magnav.min.js new file mode 100644 index 000000000..03700df14 --- /dev/null +++ b/apps/magnav/magnav.min.js @@ -0,0 +1,10 @@ +var Yoff=80,pal2color=new Uint16Array([0,65535,2047,50712],0,2),buf=Graphics.createArrayBuffer(240,50,2,{msb:!0});Bangle.setLCDTimeout(30);function flip(b,c){g.drawImage({width:240,height:50,bpp:2,buffer:b.buffer,palette:pal2color},0,c);b.clear()}var labels="N NE E SE S SW W NW".split(" "),brg=null; +function drawCompass(b){buf.setColor(1);buf.setFont("Vector",16);var c=b-90;0>c&&(c+=360);buf.fillRect(28,45,212,49);var a=30,d=15-c%15;15>d?a+=d:d=0;for(var e=d;e<=180-d;e+=15){var f=c+e;0==f%90?(buf.drawString(labels[Math.floor(f/45)%8],a-8,0),buf.fillRect(a-2,25,a+2,45)):0==f%45?(buf.drawString(labels[Math.floor(f/45)%8],a-12,0),buf.fillRect(a-2,30,a+2,45)):0==f%15&&buf.fillRect(a,35,a+1,45);a+=15}brg&&(b=brg-b,180b&&(b+=360),b+=120,30>b&&(b=14),210c?1:-1;180<=a&&(a=360-a,d=-d);if(2>a)return c;a=c+d*(1+Math.round(a/5));0>a&&(a+=360);360a&&(a+=360);return a} +function reading(){var b=tiltfixread(CALIBDATA.offset,CALIBDATA.scale);heading=newHeading(b,heading);drawCompass(heading);buf.setColor(1);buf.setFont("6x8",2);buf.setFontAlign(-1,-1);buf.drawString("o",170,0);buf.setFont("Vector",40);b=Math.round(heading);var c=b.toString();buf.drawString(10>b?"00"+c:100>b?"0"+c:c,70,10);flip(buf,Yoff+80)} +function calibrate(){var b=-32E3,c=-32E3,a=-32E3,d=32E3,e=32E3,f=32E3,k=setInterval(function(){var h=Bangle.getCompass();b=h.x>b?h.x:b;c=h.y>c?h.y:c;a=h.z>a?h.z:a;d=h.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 ZUFZJ*&=$KX>m;A`p_Hc7F2Ai$|JmSl1Fir7 literal 0 HcmV?d00001 From ee054008e42e1f4208dde9a861774f3b6c02f0e8 Mon Sep 17 00:00:00 2001 From: jeffmer Date: Tue, 9 Jun 2020 12:12:00 +0100 Subject: [PATCH 55/72] Update apps.json --- apps.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/apps.json b/apps.json index 58bdfdac2..9905462d8 100644 --- a/apps.json +++ b/apps.json @@ -1905,5 +1905,18 @@ {"name":"life.app.js","url":"life.min.js"}, {"name":"life.img","url":"life-icon.js","evaluate":true} ] + }, + { "id": "magnav", + "name": "Navigation Compass", + "icon": "magnav.png", + "version":"0.03", + "description": "Compass with linear display as for GPSNAV. Has Tilt compensation and remembers calibration.", + "readme": "README.md", + "tags": "tool,outdoors", + "storage": [ + {"name":"magnav.app.js","url":"magnav.min.js"}, + {"name":"magnav.img","url":"magnav-icon.js","evaluate":true} + ], + "data":[{"name":"magnav.json"}] } ] From cce5f479240308b48dd2cb9e7ced785eaee0132c Mon Sep 17 00:00:00 2001 From: Matjaz Lipus Date: Wed, 10 Jun 2020 08:55:01 +0200 Subject: [PATCH 56/72] updated SI date formats --- apps/locale/locales.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/locale/locales.js b/apps/locale/locales.js index 7d7f7c808..083aae696 100644 --- a/apps/locale/locales.js +++ b/apps/locale/locales.js @@ -486,7 +486,7 @@ var locales = { temperature: "°C", ampm: { 0: "dop.", 1: "pop." }, timePattern: { 0: "%HH:%MM:%SS", 1: "%HH:%MM" }, - datePattern: { 0: "%d. %b %Y", 1: "%d.%m.%Y" }, // "30. jan. 2020" // "30.01.2020"(short) + datePattern: { 0: "%-d. %b %Y", 1: "%-d.%-m.%Y" }, // "3. jan. 2020" // "3.1.2020"(short) abmonth: "jan.,feb.,mar.,apr.,maj,jun.,jul.,avg.,sep.,okt.,nov.,dec.", month: "januar,februar,marec,april,maj,junij,julij,avgust,september,oktober,november,december", abday: "ned.,pon.,tor.,sre.,čet.,pet.,sob.", From 8b6a691546aacad2fd89ac3e430f606a6cb0332c Mon Sep 17 00:00:00 2001 From: Matjaz Lipus Date: Wed, 10 Jun 2020 08:56:45 +0200 Subject: [PATCH 57/72] code format, don't use unnecessary .map --- apps/boot/boot0.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/boot/boot0.js b/apps/boot/boot0.js index 38423362d..5e69a98ca 100644 --- a/apps/boot/boot0.js +++ b/apps/boot/boot0.js @@ -42,13 +42,14 @@ if (!s.timeout) Bangle.setLCDPower(1); E.setTimeZone(s.timezone); delete s; // Draw out of memory errors onto the screen -E.on('errorFlag', function(errorFlags) { g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); - print("Interpreter error:",errorFlags); +E.on('errorFlag', function(errorFlags) { + g.reset(1).setColor("#ff0000").setFont("6x8").setFontAlign(0,1).drawString(errorFlags,g.getWidth()/2,g.getHeight()-1).flip(); + print("Interpreter error:", errorFlags); E.getErrorFlags(); // clear flags so we get called next time }); // stop users doing bad things! global.save = function() { throw new Error("You can't use save() on Bangle.js without overwriting the bootloader!"); } // Load *.boot.js files -require('Storage').list(/\.boot\.js/).map(bootFile=>{ +require('Storage').list(/\.boot\.js/).forEach(bootFile=>{ eval(require('Storage').read(bootFile)); }); From fc5595bf6a98d6d3cf96820360b370da37290909 Mon Sep 17 00:00:00 2001 From: Matjaz Lipus Date: Wed, 10 Jun 2020 08:57:24 +0200 Subject: [PATCH 58/72] use less variables --- apps/boot/bootloader.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/apps/boot/bootloader.js b/apps/boot/bootloader.js index c69bb74e6..8c61e9018 100644 --- a/apps/boot/bootloader.js +++ b/apps/boot/bootloader.js @@ -1,24 +1,20 @@ // This runs after a 'fresh' boot -var settings=require("Storage").readJSON('setting.json',1)||{}; -// load clock if specified -var clockApp = settings.clock; +var clockApp=(require("Storage").readJSON("setting.json",1)||{}).clock; if (clockApp) clockApp = require("Storage").read(clockApp); if (!clockApp) { - var clockApps = require("Storage").list(/\.info$/).map(app=>require("Storage").readJSON(app,1)||{}).filter(app=>app.type=="clock").sort((a, b) => a.sortorder - b.sortorder); - if (clockApps && clockApps.length) - clockApp = require("Storage").read(clockApps[0].src); - delete clockApps; + clockApp = require("Storage").list(/\.info$/).map(a=>require("Storage").readJSON(a,1)||{}).filter(a=>a.type=="clock").sort((a, b) => a.sortorder - b.sortorder)[0]; + if (clockApp) + clockApp = require("Storage").read(clockApp.src); } if (!clockApp) clockApp=`E.showMessage("No Clock Found"); setWatch(() => { Bangle.showLauncher(); }, BTN2, {repeat:false,edge:"falling"});) `; -delete settings; // check to see if our clock is wrong - if it is use GPS time if ((new Date()).getFullYear()<2000) { E.showMessage("Searching for\nGPS time"); - Bangle.on('GPS',function cb(g) { + Bangle.on("GPS",function cb(g) { Bangle.setGPSPower(0); Bangle.removeListener("GPS",cb); if (!g.time || (g.time.getFullYear()<2000) || From ca0dcb53d7d83db20deec3022c54da0c0638815e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 10 Jun 2020 08:26:38 +0100 Subject: [PATCH 59/72] bump bootloader version --- apps.json | 2 +- apps/boot/ChangeLog | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps.json b/apps.json index 9905462d8..48428fb76 100644 --- a/apps.json +++ b/apps.json @@ -2,7 +2,7 @@ { "id": "boot", "name": "Bootloader", "icon": "bootloader.png", - "version":"0.18", + "version":"0.19", "description": "This is needed by Bangle.js to automatically load the clock, menu, widgets and settings", "tags": "tool,system", "type":"bootloader", diff --git a/apps/boot/ChangeLog b/apps/boot/ChangeLog index fc67fe6b7..17d35a36c 100644 --- a/apps/boot/ChangeLog +++ b/apps/boot/ChangeLog @@ -17,3 +17,4 @@ 0.16: Detect out of memory errors and draw them onto the bottom of the screen in red 0.17: Don't modify beep/buzz behaviour if firmware does it automatically 0.18: Fix 'GPS time' checks for western hemisphere +0.19: Tweaks to simplify code and lower memory usage From f4859dc269f13006458649ffb5e97d8d80db304e Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Wed, 10 Jun 2020 08:27:26 +0100 Subject: [PATCH 60/72] lint fix --- js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/index.js b/js/index.js index 0c1662a27..bc90fcdbb 100644 --- a/js/index.js +++ b/js/index.js @@ -403,7 +403,7 @@ function checkDependencies(app, uploadOptions) { if (found) console.log(`Found dependency in installed app '${found.id}'`); else { - var foundApps = appJSON.filter(app=>app.type==dependency); + let foundApps = appJSON.filter(app=>app.type==dependency); if (!foundApps.length) throw new Error(`Dependency of '${dependency}' listed, but nothing satisfies it!`); console.log(`Apps ${foundApps.map(f=>`'${f.id}'`).join("/")} implement '${dependency}'`); found = foundApps[0]; // choose first app in list From e0a5f062a4294c48d7d17bf66274d95d1b63253a Mon Sep 17 00:00:00 2001 From: Matjaz Lipus Date: Wed, 10 Jun 2020 10:04:48 +0200 Subject: [PATCH 61/72] load only clock apps --- apps/boot/bootloader.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/apps/boot/bootloader.js b/apps/boot/bootloader.js index 8c61e9018..df3718dcc 100644 --- a/apps/boot/bootloader.js +++ b/apps/boot/bootloader.js @@ -2,7 +2,15 @@ var clockApp=(require("Storage").readJSON("setting.json",1)||{}).clock; if (clockApp) clockApp = require("Storage").read(clockApp); if (!clockApp) { - clockApp = require("Storage").list(/\.info$/).map(a=>require("Storage").readJSON(a,1)||{}).filter(a=>a.type=="clock").sort((a, b) => a.sortorder - b.sortorder)[0]; + clockApp = require("Storage").list(/\.info$/) + .map(file => { + const app = require("Storage").readJSON(file,1); + if (app && app.type == "clock") { + return app; + } + }) + .filter(x=>x) + .sort((a, b) => a.sortorder - b.sortorder)[0]; if (clockApp) clockApp = require("Storage").read(clockApp.src); } From cb4df2d7c68dc7cdbe29f3b7aa9798298a855c8f Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 11 Jun 2020 13:37:55 +0100 Subject: [PATCH 62/72] GPS POI Logger - A simple app to log points of interest with their GPS coordinates and read them back onto your PC. Based on the https://www.espruino.com/Bangle.js+Storage tutorial --- apps.json | 13 +++++++ apps/gpspoilog/ChangeLog | 1 + apps/gpspoilog/app-icon.js | 1 + apps/gpspoilog/app.js | 67 +++++++++++++++++++++++++++++++++ apps/gpspoilog/app.png | Bin 0 -> 1366 bytes apps/gpspoilog/interface.html | 69 ++++++++++++++++++++++++++++++++++ 6 files changed, 151 insertions(+) create mode 100644 apps/gpspoilog/ChangeLog create mode 100644 apps/gpspoilog/app-icon.js create mode 100644 apps/gpspoilog/app.js create mode 100644 apps/gpspoilog/app.png create mode 100644 apps/gpspoilog/interface.html diff --git a/apps.json b/apps.json index 48428fb76..0fb69b9cf 100644 --- a/apps.json +++ b/apps.json @@ -1918,5 +1918,18 @@ {"name":"magnav.img","url":"magnav-icon.js","evaluate":true} ], "data":[{"name":"magnav.json"}] + }, + { "id": "gpspoilog", + "name": "GPS POI Logger", + "shortName":"GPS POI Log", + "icon": "app.png", + "version":"0.01", + "description": "A simple app to log points of interest with their GPS coordinates and read them back onto your PC. Based on the https://www.espruino.com/Bangle.js+Storage tutorial", + "tags": "outdoors", + "interface": "interface.html", + "storage": [ + {"name":"gpspoilog.app.js","url":"app.js"}, + {"name":"gpspoilog.img","url":"app-icon.js","evaluate":true} + ] } ] diff --git a/apps/gpspoilog/ChangeLog b/apps/gpspoilog/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/gpspoilog/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/gpspoilog/app-icon.js b/apps/gpspoilog/app-icon.js new file mode 100644 index 000000000..89f8d1bd7 --- /dev/null +++ b/apps/gpspoilog/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AEeGAAwttGMotLGMItPGLwuTGDQuVGDIfHq9RAAgvfDw+AFwtRq4weFZYAIwAvYJIguPSowvavl8F8qpFF6wwSF44AFvl9vo3GF8l80+t1unGAovkvovDvovrAAQvqR4IACR9TviGAovHABIuXF/4vgGAmAFx+AFzDxGACYvVGDAuWF+AwWFzAvwGCguaGCYucF+AwQFzwvwGBwugGBouiF+AwKF0gwJF0wwHF1AvwGAguqGAYusAH4A/AFI=")) diff --git a/apps/gpspoilog/app.js b/apps/gpspoilog/app.js new file mode 100644 index 000000000..2da0c0e7e --- /dev/null +++ b/apps/gpspoilog/app.js @@ -0,0 +1,67 @@ +var menuItems = { + "":{title:"GPS POI Log"}, + " ":{value:"No Fix"}, + "Tree" : ()=>addItem("Tree"), + "Gate" : ()=>addItem("Gate"), + "Flower" : ()=>addItem("Flower"), + "Plant" : ()=>addItem("Plant"), + "Bus Stop" : ()=>addItem("Bus Stop"), + "Pub" : ()=>addItem("Pub") +}; + +var menu = E.showMenu(menuItems); +var gps = { fix : 0}; +var gpsCount = 0; +var file = require("Storage").open("gpspoilog.csv","a"); + +function setStatus(msg) { + menuItems[" "].value = msg; + menu.draw(); +} + +Bangle.on('GPS',function(g) { + gps = g; + gpsCount++; + var msg; + if (g.fix) { + msg = g.satellites + " Satellites"; + } else { + msg = "No Fix"; + } + setStatus(msg+" "+"-\\|/"[gpsCount&3]); +}); + + +function addItem(name) { + if (!gps.fix) { + setStatus("Ignored - no fix"); + return; // don't do anything as no fix + } + // The fields we want to put in out CSV file + var csv = [ + 0|getTime(), // Time to the nearest second + gps.lat, + gps.lon, + gps.alt, + name + ]; + // Write data here + file.write(csv.join(",")+"\n"); + setStatus("Written"); +} + + +Bangle.loadWidgets(); +Bangle.drawWidgets(); +Bangle.setGPSPower(1); + + + +function getData(callback) { + var f = require("Storage").open("gpspoilog.csv","r"); + var l = f.readLine(); + while (l!==undefined) { + callback(l); + l = f.readLine(); + } +} diff --git a/apps/gpspoilog/app.png b/apps/gpspoilog/app.png new file mode 100644 index 0000000000000000000000000000000000000000..b323bb283e0bd92d266330ac70a30747d54fc661 GIT binary patch literal 1366 zcmV-c1*!UpP)~mlm)5r=cSB~1-SKIv+v!6lhRY0wRa)DXHA~yss zDdebD94@-pcPtn@n9PN4)(Ny9+Y;z=1~x0C5qQv0^s0#ZXlA@{SFrYz!EE%iN}w$g z3TokF1tlKk{}$1Wp_Nmy=m=0|$o%X#nsO4dAjs^?wTG&ja=kx)>C1DR~je_u}b zky1qNbzLxbkd<2_XmBf_IC-tA(83UwMCrlEz`pNnuoh z+oi?NGR`J7c(o9K#Z_|wI2XB=?n~$-u|xu`1pwPp_bCICZ9rSTc@nDSUS38KP8X%@LR`;&MYfVu{oUuc&;Sr&lg!PHC!r_9IIG2zPW6 z(}_tF5aBTsJ=4o*k)a()o!Uq%%1SAm1Gba;7S4u+Wn}!QI4DF86_Z!AAyZV4lN7E_7h9S33qf7 z?&!RyKhNizbO8^G{$!$OR7=M{co?{CVhfPx_Yv?r*!Erbwq+CWJ2*bSiHm_~z<0#N z&?tcyEB6fud^fh;DVlhl`D~j4e;zaP1I)+|P~bS@j=WPmG!9!1y|Q$-(SRA>joPT4 zW7{g${ysqfW^js!s94)|U%S@ob5kF#&I7IC(9ghgZa5zBOMP|A^QOkGPGlD94M<W1L@Oq>+;I$(B7>C&~fPTkkZ}&pnQ<%-l}<@0VlljMCuYDN!c?qXYOj&=#t;uDaRtKzObIK&YxU zBBFMA<%_6Kvk4xuOaMSDwu1W81NCC8z?bzp$~u8f)y;QA>GeR|1ubEr)|=k2WkS{o zKzb^DU`$Z*ezsF*1UX3nps3)+JHTlJ)6+Ba`&>VTo(MThAh`5k%(kr{nGZg9M9I3~ z(u1*F>E + + + + +
+ + + + + + + From fa169c3bef6797980ef684dfa8704f0e0a40e840 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Thu, 11 Jun 2020 15:06:22 +0100 Subject: [PATCH 63/72] revert accidental commits --- .vscode/launch.json | 17 -- apps.json | 30 +- apps/dalekcontrol/README.md | 50 ---- apps/dalekcontrol/app-icon.js | 1 - apps/dalekcontrol/app.js | 450 ---------------------------- apps/dalekcontrol/dalek_icon_30.png | Bin 7042 -> 0 bytes apps/k9control/README.md | 50 ---- apps/k9control/app-icon.js | 1 - apps/k9control/app.js | 446 --------------------------- apps/k9control/k9_icon_30.png | Bin 4779 -> 0 bytes 10 files changed, 1 insertion(+), 1044 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 apps/dalekcontrol/README.md delete mode 100644 apps/dalekcontrol/app-icon.js delete mode 100644 apps/dalekcontrol/app.js delete mode 100644 apps/dalekcontrol/dalek_icon_30.png delete mode 100644 apps/k9control/README.md delete mode 100644 apps/k9control/app-icon.js delete mode 100644 apps/k9control/app.js delete mode 100644 apps/k9control/k9_icon_30.png diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 771354e66..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Launch Program", - "skipFiles": [ - "/**" - ], - "program": "${workspaceFolder}/http-server" - } - ] -} \ No newline at end of file diff --git a/apps.json b/apps.json index 5e4a2b4a5..7aaf66a13 100644 --- a/apps.json +++ b/apps.json @@ -1811,35 +1811,7 @@ { "name": "BLEcontroller.app.js", "url": "app.js" }, { "name": "BLEcontroller.img", "url": "app-icon.js", "evaluate": true } ] - }, - { "id": "k9control", - "name": "K9 BLE Controller with Joystick", - "shortName": "K9 Controller", - "icon": "k9_icon_30.png", - "version": "0.01", - "description": "My private K9 BLE controller", - "tags": "tool,bluetooth", - "readme": "README.md", - "allow_emulator":false, - "storage": [ - { "name": "k9control.app.js", "url": "app.js" }, - { "name": "k9control.img", "url": "app-icon.js", "evaluate": true } - ] - }, - { "id": "dalekcontrol", - "name": "Dalek BLE Controller with Joystick", - "shortName": "Dalek Controller", - "icon": "dalek_icon_30.png", - "version": "0.01", - "description": "My private Dalek BLE controller", - "tags": "tool,bluetooth", - "readme": "README.md", - "allow_emulator":false, - "storage": [ - { "name": "dalekcontrol.app.js", "url": "app.js" }, - { "name": "dalekcontrol.img", "url": "app-icon.js", "evaluate": true } - ] - }, + }, { "id": "widviz", "name": "Widget Visibility Widget", "shortName":"Viz Widget", diff --git a/apps/dalekcontrol/README.md b/apps/dalekcontrol/README.md deleted file mode 100644 index 3ffe7f514..000000000 --- a/apps/dalekcontrol/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Dalek Controller - -A highly customisable state machine driven user interface that will communicate with another BLE device. The controller uses the three buttons and the left and right hand side of the watch to provide a flexible and attractive BLE interface. - -Amaze your friends by controlling your robot, your house or any other BLE device from your watch! - - - -To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: -* message number (up to the least significant four digits) -* screen name (up to four characters) -* object name (up to four characters) -* value/status (up to four characters) - -The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. - -Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) -/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# - -## Usage - -The application can be configured at will by changing the definitions of the screens, events, icons and buttons. - -Most changes are possible via data, rather than code change. - -## Features - -The default package contains three configurations: -* a simple home light and sockets controller UI (app.js) -* a robot controller UI with joystick (app-joy.js) -* a simple static assistant controller (app-ex2.js) - -You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. - -I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. - -## Controls - -The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. - -I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) - -## Requests - -In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) - -## Creator - -Richard Hopkins, FIET CEng -May 2020 diff --git a/apps/dalekcontrol/app-icon.js b/apps/dalekcontrol/app-icon.js deleted file mode 100644 index b228e290b..000000000 --- a/apps/dalekcontrol/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -E.toArrayBuffer(atob("Hh6EAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACIAAAAAAAAAAAAAAAACIiIiIAAAAAAAACIgAAIiICICIiAAAiIAACIiAiIiAgAgIiIgIiIAAAIgIiIiAAACIiIiAiAAAAAiIiIiAAACIiIiIgAAAAACIiIiAgAAIiIiIAAAAAAiIiIiICIgIiIiIgAAAAAiIiIiIgAiIiIiIgAAAAAiIiIiIiIiIiIiIgAAAAAiACIAAAAAACIAIgAAAAAgAAIAAAAAAAIAAgAAAAIiIiIiIiIiIiIiIiAAAAIiIiIiIiIiIiIiIiAAAAAAAAIAAAAAAAIAAAAAAAIAAAIAAAAAAAIAACAAAAIAAAIAAAAAAAIAACAAACIiIiIiIiIiIiIiIiIAACIAACIAAAAAACIAACIAAAIAAAIAAAAAAAIAACAAACIAACIAAAAAACIAACIAAiIiIiIiIiIiIiIiIiIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")) diff --git a/apps/dalekcontrol/app.js b/apps/dalekcontrol/app.js deleted file mode 100644 index 27e629d5d..000000000 --- a/apps/dalekcontrol/app.js +++ /dev/null @@ -1,450 +0,0 @@ -/* -========================================================== -Simple event based robot controller that enables robot -to switch into automatic or manual control modes. Behaviours -are controlled via a simple finite state machine. -In automatic mode the -robot will look after itself. In manual mode, the watch -will provide simple forward, back, left and right commands. -The messages will be transmitted to a partner BLE Espruino -using BLE -Written by Richard Hopkins, May 2020 -========================================================== -declare global variables for watch button statuses */ -top_btn = false; -middle_btn = false; -left_btn= false; // the left side of the touch screen -right_btn = false; // the right side of the touch screen -bottom_btn = false; - -msgNum = 0; // message number - -/* -CONFIGURATION AREA - STATE VARIABLES -declare global variables for the toggle button -statuses; if you add an additional toggle button -you should declare it and initiase it here */ - -var status_spk = {value: true}; -var status_face = {value: true}; -var status_iris_light = {value: false}; -var status_iris = {value: false}; -var status_hover = {value: false}; -var status_dome = {value: false}; - -/* trsnsmit message -where -s = first character of state, -o = first three character of object name -v = value of state.object -*/ - -const transmit = (state,object,status) => { - msgNum ++; - msg = { - n: msgNum.toString().slice(-4), - s: state.substr(0,4), - o: object.substr(0,4), - v: status.substr(0,4), - }; - message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; - NRF.setAdvertising({},{ - showName: false, - manufacturer: 0x0590, - manufacturerData: JSON.stringify(message)}); -}; - -/* -CONFIGURATION AREA - ICON DEFINITIONS -Retrieve 30px PNG icons from: -https://icons8.com/icon/set/speak/ios-glyphs -Create icons using: -https://www.espruino.com/Image+Converter -Use compression: true -Transparency: true -Diffusion: flat -Colours: 16bit RGB -Ouput as: Image Object -Add an additional element to the icons array -with a unique name and the data from the Image Object -*/ -const icons = [ - { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "spk_on", - data: "gEBAP4B/AP4Bic/YAFPP4v1HrYZRVJo7ZDKp5jMJYvZHaYAHVL4LHACZrhADLBTJKI7dPLI7/Hf47/HeZBVFqZHZRJp1lAJ47LOtZTnHbIZDKLpHNAL69ZANp1tQbY5/AP4B/ANQ" - }, - { - name: "spk_off", - data: "gEBAPhB7P/o9rFKI9pFKY9tXNYZNHrZXfMaoAHPOZhNF7LdXHpKpZEJpvPDZK1ZAB49NPLo9jHdI9NHd49PHebvxEJY9NI6I7dHpaDXcKqfPHLKjZHcpTjHbIZDKa73JHa4BXGY45xe5Y7zV+o9/Hv49JHe4BEA=" - }, - { - name: "facerecog", - data: "gEBAP4BSLuozNH9YpTHsolXPsYfdDraZhELIZhHeLtJELY1VC4Y7HHqoXJABYdNHa5bJDrLvfHfbrPZJI7nGZpdVNJ4lRIpaznRqp1hCq55ZC6IRPd8oPjW8Y5jSr45dEJppNHcIjLHZY5ja6rrhFK45pVqI5rGI4AHHNpx3ANA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "happy", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/HtInTCZrfZHa4vNABYlVKLI3PbLrzfD7qTXDLaphHMIpLAB45hIKY1pAP4B/AMA" - }, - { - name: "sad", - data: "gEBAP4B/AP4BKa+oAXHNITfHK4ZtD5JZfHOojZaMYlXHMYnXHfI5nFaYPLaaIRNHf47/d/47/CK4njCZ4APHcIVJBbbdTecYjZHr4fdSa4ZbEZ4lNCaY9dAB45hIKY1pAP4B/AMA" - }, - { - name: "hover", - data: "gEBAP4B/AP7NedL4fZK7ojNHeJ35DJI7vC5Y7tVMI7XHNYnNYro7hHKI7lAK47/HdoAhHPI7/Hf47/Hf4AtHPI7/Hf47/Hd45LAP4B/ANwA=" - }, - { - name: "light", - data: "gEBAP4B/APi/Na67lfACZ/nNaI9lE6o9jEbI9hD7Y7dDsJZ3D6YRJHdIJHHfaz7Hf5Z/Hf4hZHMIjFEqIVVHsY5hDpI7TEqL1jVsqlTdM55THOJvHOuY7/HfI9JHOI9HHOoBgA==" - }, - { - name: "speak", - data: "gEBAP4B/AP4BIbO4AXG+4/hAEY55HqoArHPI9PHfIAzHf47/Hf47/HeY9xHJI79Hto5NHtY5RHc45THco5VHcI3XHJpHRG7I7LEro5ZG+IB/AP4BwA==" - }, - { - name: "dalek", - data: "gEBAP4B/AP4B/AJMQwQBBGucIoMAkADBhFhAoZBcAAQfJhEgB45BCHYMBjGiB4ZLCK5APDFpphBC5AbEJosY0YfCG4IAEJIYdGFYR5LHJYlEAI0Y4cY8YXMOpQBFlNFlMkOZA7MKII7JOAXkE4T1UERKtFHoxJBABY5QiGiD5kANYTnCiFiWIJVOgDZCOra3FoKxFDKI7hADQ7PkEIaoIHEaKYfJAoKPFAJcIGYIJHkI7UgMY8ZFHC5rVDKIZTCDIJhBA4ILBBoYFHC4QBEBogpBjHDdsJJEAoYAHKoTxWWb5tNWZOiHZRbBHbwtLF5ynBL7wtLjHjd6oAZkHkI5JJKAAZ3TkAjJhALBsJ5K0a/KkLvfkMEFpVhO8hrIU4QLGG4QAzkCdVAP4B/AP4Bb" - } - ]; - -/* finds icon data by name in the icon array and returns an image object*/ -const drawIcon = (name) => { - for (var icon of icons) { - if (icon.name == name) { - image = { - width : 30, height : 30, bpp : 16, - transparent : 1, - buffer: require("heatshrink").decompress(atob(icon.data)) - }; - return image;} - } -}; - -/* -CONFIGURATION AREA - BUTTON DEFINITIONS -for a simple button, just define a primary colour -and an icon name from the icon array and -the text to display beneath the button -for toggle buttons, additionally provide secondary -colours, icon name and text. Also provide a reference -to a global variable for the value of the button. -The global variable should be declared at the start of -the program and it may be adviable to use the 'status_name' -format to ensure it is clear. -*/ - -var happyBtn = { - primary_colour: 0x653E, - primary_text: 'Speak', - primary_icon: 'happy', - }; - -var sadBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'sad', - }; - -var speakBtn = { - primary_colour: 0x33F9, - primary_text: 'Speak', - primary_icon: 'speak', - }; - -var faceBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'facerecog', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'facerecog', - value: status_face - }; - -var irisLightBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'light', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'light', - value: status_iris_light - }; - -var irisBtn = { - primary_colour: 0xE9C7, - primary_text: 'Closed', - primary_icon: 'sleep', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Open', - secondary_icon : 'awake', - value: status_iris - }; - -var hoverBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'hover', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'hover', - value: status_hover - }; - - var domeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'dalek', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'dalek', - value: status_dome - }; - -/* -CONFIGURATION AREA - SCREEN DEFINITIONS -a screen can have a button (as defined above) -on the left and/or the right of the screen. -in adddition a screen can optionally have -an icon for each of the three buttons on -the left hand side of the screen. These -are defined as btn1, bt2 and bt3. The -values are names from the icon array. -*/ - -const menuScreen = { - left: faceBtn, - right: speakBtn, - btn1: "hover", - btn2: "light", -}; - -const speakScreen = { - left: happyBtn, - right: sadBtn, - btn3: "back" -}; - -const irisScreen = { - left: irisBtn, - right: irisLightBtn, - btn3: "back" -}; - -const lightsScreen = { - left: hoverBtn, - right: domeBtn, - btn3: "back" -}; - -/* base state definition -Each of the screens correspond to a state; -this class provides a constuctor for each -of the states -*/ -class State { - constructor(params) { - this.state = params.state; - this.events = params.events; - this.screen = params.screen; - } -} - -/* -CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS -This area defines how each screen behaves. -Each screen corresponds to a different State of the -state machine. This makes it much easier to isolate -behaviours between screens. -The state value is transmitted whenever a button is pressed -to provide context (so the receiving device, knows which -button was pressed on which screen). -The screens are defined above. -The events section identifies if a particular button has been -pressed and released on the screen and an action can then be taken. -The events function receives a notification from a mySetWatch which -provides an event object that identifies which button and whether -it has been pressed down or released. Actions can then be taken. -The events function will always return a State object. -If the events function returns different State from the current -one, then the state machine will change to that new State and redrsw -the screen appropriately. -To add in additional capabilities for button presses, simply add -an additional 'if' statement. -For toggle buttons, the value of the sppropiate status object is -inversed and the new value transmitted. -*/ - -/* The Home State/Page is where the application beings */ - -const Home = new State({ - state: "DalekMenu", - screen: menuScreen, - events: (event) => { - if ((event.object == "top") && (event.status == "end")) { - return Lights; - } - if ((event.object == "middle") && (event.status == "end")) { - return Iris; - } - if ((event.object == "right") && (event.status == "end")) { - return Speak; - } - if ((event.object == "left") && (event.status == "end")) { - status_face.value = !status_face.value; - transmit(this.state, "face", onOff(status_face.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Speak = new State({ - state: "Speak", - screen: speakScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Iris = new State({ - state: "Iris", - screen: irisScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_iris_light.value = !status_iris_light.value; - transmit(this.state, "light", onOff(status_iris_light.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_iris.value = !status_iris.value; - transmit(this.state, "servo", onOff(status_iris.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Lights = new State({ - state: "Lights", - screen: lightsScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_dome.value = !status_dome.value; - transmit(this.state, "dome", onOff(status_dome.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_hover.value = !status_hover.value; - transmit(this.state, "hover", onOff(status_hover.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* translate button status into english */ -const startEnd = status => status ? "start" : "end"; - -/* translate status into english */ -const onOff= status => status ? "on" : "off"; - - -/* create watching functions that will change the global -button status when pressed or released -This is actuslly the hesrt of the program. When a button -is not being pressed, nothing is happening (no loops). -This makes the progrsm more battery efficient. -When a setWatch event is raised, the custom callbacks defined -here will be called. These then fired as events to the current -state/screen of the state mschine. -Some events, will result in the stste of the state machine -chsnging, which is why the screen is redrswn after each -button press. -*/ -const setMyWatch = (params) => { - setWatch(() => { - params.bool=!params.bool; - machine = machine.events({object: params.label, status: startEnd(params.bool)}); - drawScreen(machine.screen); - }, params.btn, {repeat:true, edge:"both"}); -}; - -/* object array used to set up the watching functions -*/ -const buttons = [ - {bool : bottom_btn, label : "bottom",btn : BTN3}, - {bool : middle_btn, label : "middle",btn : BTN2}, - {bool : top_btn, label : "top",btn : BTN1}, - {bool : left_btn, label : "left",btn : BTN4}, - {bool : right_btn, label : "right",btn : BTN5} - ]; - -/* set up watchers for buttons */ -for (var button of buttons) - {setMyWatch(button);} - -/* Draw various kinds of buttons */ -const drawButton = (params,side) => { - g.setFontAlign(0,1); - icon = drawIcon(params.primary_icon); - text = params.primary_text; - g.setColor(params.primary_colour); - const x = (side == "left") ? 0 : 120; - if ((params.toggle) && (params.value.value)) { - g.setColor(params.secondary_colour); - text = params.secondary_text; - icon = drawIcon(params.secondary_icon); - } - g.fillRect(0+x,24,119+x, 239); - g.setColor(0x000); - g.setFont("Vector",15); - g.setFontAlign(0,0.0); - g.drawString(text,60+x,160); - options = {rotate: 0, scale:2}; - g.drawImage(icon,x+60,120,options); -}; - -/* Draw the pages corresponding to the states */ -const drawScreen = (params) => { - drawButton(params.left,'left'); - drawButton(params.right,'right'); - g.setColor(0x000); - if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} - if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} - if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} -}; - -machine = Home; // instantiate the state machine at Home -Bangle.drawWidgets(); // draw active widgets -drawScreen(machine.screen); // draw the screen diff --git a/apps/dalekcontrol/dalek_icon_30.png b/apps/dalekcontrol/dalek_icon_30.png deleted file mode 100644 index b59750e9d716d2f67290004367bb3a746f9e6f8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7042 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 - -To keep the messages small, commands are sent from the Controller to the BLE target in a text string. This is made up of a comma delimited string of the following elements: -* message number (up to the least significant four digits) -* screen name (up to four characters) -* object name (up to four characters) -* value/status (up to four characters) - -The combination of these variables will uniquely identify the status change requested from the watch to the target device that can then be programmed to respond appropriately. - -Gordon Williams' EspruinoHub is an excellent way to transform thse BLE advertisements into MQTT messages for further processing. They can be subscribed to via the following MQTT topic (change the watchaddress, to the MAC address of your Bangle.js) -/ble/advertise/wa:tc:ha:dd:re:ss/espruino/# - -## Usage - -The application can be configured at will by changing the definitions of the screens, events, icons and buttons. - -Most changes are possible via data, rather than code change. - -## Features - -The default package contains three configurations: -* a simple home light and sockets controller UI (app.js) -* a robot controller UI with joystick (app-joy.js) -* a simple static assistant controller (app-ex2.js) - -You can try out the other configurations by deleting app.js and renaming the file you want to try as app.js. - -I have tested out the application to as many as eight screens without problems, but four screens are usually enough for most situations. - -## Controls - -The controls will vary by screen, but I suggest a convention of using BTN3 (the bottom button) for moving backwards up the menu stack. - -I have used the convention of red/green for buttons that are switches and blue buttons that provide single function operation (such as navigating a menu or executing a on-off activity) - -## Requests - -In the first instance, please consult my blog post on this application [here](https://k9-build.blogspot.com/2020/05/controlling-k9-using-bluetooth-ble-from.html) - -## Creator - -Richard Hopkins, FIET CEng -May 2020 diff --git a/apps/k9control/app-icon.js b/apps/k9control/app-icon.js deleted file mode 100644 index 55d7fb3cc..000000000 --- a/apps/k9control/app-icon.js +++ /dev/null @@ -1 +0,0 @@ -E.toArrayBuffer(atob("JyeEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAAAAAAiAAAAAAAAAAAAAAAAAAAAACIiIiAAAAAAAAAAAAAAAAAAAAACIiIgAAAAIAAAAAAAAAAAAAAAAiIiIiIAAAAiAAAAAAAAAAAAAAAiIiIiIAAAACIiAAAAAAAAAAAAAiIiIiIAAAAAAiIgAAAiIiIiIgAiIiIiIiAAAAAAIiIiIiIiIiIiIiIiIiIiIAAAAAACIiIiIiIiIiIiIiIiIiIgAAAAAAIiIiIiIiIiIiIiIiIiIiAAAAAAIiIiIiIiIiIiIgAiIiIgAAAAACIiIiIiIiIiIiIAACIiIAAAAAAiIiIiIiIiIiIiAAAAAAAAAAAAIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAAiIiIiIiIiIiIiIiAAAAAAAAAAAiIiIiIiIiIiIiIiIAAAAAAAAAAiIiIiIiIiIiIiIiIAAAAAAAAAIiIiIiIiIiIiIiIiIAAAAAAAAAIiIiIiIiIiIiIiIiIgAAAAAAACIiIiIiIiIiIiIiIiIgAAAAAAACIiIiIiIiIiIiIiIiIiAAAAAAAAACIiIiIiIiIiIiIiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")) diff --git a/apps/k9control/app.js b/apps/k9control/app.js deleted file mode 100644 index 0735aeee6..000000000 --- a/apps/k9control/app.js +++ /dev/null @@ -1,446 +0,0 @@ -/* -========================================================== -Simple event based robot controller that enables robot -to switch into automatic or manual control modes. Behaviours -are controlled via a simple finite state machine. -In automatic mode the -robot will look after itself. In manual mode, the watch -will provide simple forward, back, left and right commands. -The messages will be transmitted to a partner BLE Espruino -using BLE -Written by Richard Hopkins, May 2020 -========================================================== -declare global variables for watch button statuses */ -top_btn = false; -middle_btn = false; -left_btn= false; // the left side of the touch screen -right_btn = false; // the right side of the touch screen -bottom_btn = false; - -msgNum = 0; // message number - -NRF.setConnectionInterval(100); -Bangle.loadWidgets(); -Bangle.drawWidgets(); -/* -CONFIGURATION AREA - STATE VARIABLES -declare global variables for the toggle button -statuses; if you add an additional toggle button -you should declare it and initiase it here */ - -var status_auto = {value: false}; -var status_chess = {value: false}; -var status_wake = {value: false}; - -/* trsnsmit message -where -s = first character of state, -o = first three character of object name -v = value of state.object -*/ - -const transmit = (state,object,status) => { - msgNum ++; - msg = { - n: msgNum.toString().slice(-4), - s: state.substr(0,4), - o: object.substr(0,4), - v: status.substr(0,4), - }; - message= msg.n + "," + msg.s + "," + msg.o + "," + msg.v; - NRF.setAdvertising({},{ - showName: false, - manufacturer: 0x0590, - manufacturerData: JSON.stringify(message)}); -}; - -/* -CONFIGURATION AREA - ICON DEFINITIONS -Retrieve 30px PNG icons from: -https://icons8.com/icon/set/speak/ios-glyphs -Create icons using: -https://www.espruino.com/Image+Converter -Use compression: true -Transparency: true -Diffusion: flat -Colours: 16bit RGB -Ouput as: Image Object -Add an additional element to the icons array -with a unique name and the data from the Image Object -*/ -const icons = [ - { - name: "walk", - data: "gEBAP4B/ALyh7b/YALHfY9tACY55HfYdNHto7pHpIbXbL5fXAD6VlHuYAjHf47/Hf47tHK47LDa45zHc4NHHeILJHeonTO9o9rHf47/eOoB/ANg=" - }, - { - name: "sit", - data: "gEBAP4B/AP4BacO4ANHPI/rACp1/Hf49rGtI5/He7n3ACY55HcYAZHf45/Hf45rHe4XHGbI7/Va47zZZrpbHfbtXD5Y/vHcYB/AP4BmA" - }, - { - name: "joystick", - data: "gEBAP4B/AP4BMavIALHPI9vHf47/eP45vHpY5xHo451Hf47/FuYAHHNItHABa33AP6xpAD455HqY7/Hf47/Hd49pHKIB/AP4B/AMwA==" - }, - { - name: "left", - data: "gEBAP4B/AP4BKa9ojHAC5pfHJKDTUsYdZHb6ZfO+I9dABabdLbIBdHf473PP47NJdY7/ePIB/RJop5Ys7t/AP6PvD7o7fP8Y1zTZoHPf/4B/AP4B+A==" - }, - { - name: "right", - data: "gEBAP4B/AP4BKa+oAXDo45hCaqFbUbLBfbbo7bHMojTR7Y5LHa51ZALo75Ov47/FeY77AP4B5WdbF3dv4B/R94fdHb5/jGuabNA57//AP4B/APw=" - }, - { - name: "forward", - data: "gEBAP4B/AKSX5avIALHPI9tACY55HsoAbHPI9fHfZFVGMo7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/Hf49XHOIB/ALw=" - }, - { - name: "backward", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/Hf47/Hf47/Hf47/HfIAfHf491W/L15HMo9THNI9PHNo9LHOI9HHOoB/ALg=" - }, - { - name: "back", - data: "gEBAP4B/AP4B/AKgADHPI71HP45/HP45/HP45/HP45/Hf49/Hv49/Hv49/Hv49/Hv497He4B/AP4B/AJAA==" - }, - { - name: "mic_on", - data: "gEBAP4B/AKCZ5a/Y7/Hf47/Hf47/Hf47/GbY7TIcY7/Hf47/Hf47/HdY9NCpp5lCb57fOdYvNeJo91HNrlvHf7tVIdY77AP4BiA=" - }, - { - name: "comms", - data: "gEBAP4B+QvbF7ABo7/He49tACI7/Hf47zHtI7jJq47lRqoAVEqY7nHsoAZGJo71HrKxfQaY7bdKo7/Hdqz5B5Y7zHK47RD55FRHao3XHKo7JG7L1NHeJTbHboB/AP4BG" - }, - { - name: "pawn", - data: "gEBAP4B/AP4B/AP4BEAA455HuY7/Hf47xAB47/PuI1xPZY7/Hf47/G9Y/zHfIATHPI9nHfYB/AOYAfHf4B/AP4B/APA=" - }, - { - name: "sleep", - data: "gEBAP4B/AP4B2ACY7/Quq95HP45/HP4APOdY7fACZfnHcaZZAL45/HP45/E7YAHCaZFZHfbh/HP45/HOoAHHf4B/AP4B/AP4BIA=" - }, - { - name: "awake", - data: "gEBAP4B/AKyb7HfIAFHPI77Ov451Hf453Hf453HdoAbHf45/Hf5HrHNY7NHNo7/HO47/HO47HHPJ1/Heo51HfoB/ALg=" - }, - { - name: "wag_h", - data: "gEBAP4B/AP4B/AP4B/AP4B/AMwADD+oAFHb4hTHMIlXHMopTHNItPAG47/WfY9tFKY9lEq49hELY7ja8YB/AP4B/AP4B/AP4B/AP4BCA" - }, - { - name: "wag_v", - data: "gEBAP4B/AP4BOafIAHHPI9xAB45vd449rFZIHLHsonJBKa7rGNo7/Hf47/Hf47/Hf47/Hf4xlBKY7hFIoHLQM4rHApK7rAB71xHOo9LHOI9HHOoB/AP4BYA=" - } - ]; - -/* finds icon data by name in the icon array and returns an image object*/ -const drawIcon = (name) => { - for (var icon of icons) { - if (icon.name == name) { - image = { - width : 30, height : 30, bpp : 16, - transparent : 1, - buffer: require("heatshrink").decompress(atob(icon.data)) - }; - return image;} - } -}; - -/* -CONFIGURATION AREA - BUTTON DEFINITIONS -for a simple button, just define a primary colour -and an icon name from the icon array and -the text to display beneath the button -for toggle buttons, additionally provide secondary -colours, icon name and text. Also provide a reference -to a global variable for the value of the button. -The global variable should be declared at the start of -the program and it may be adviable to use the 'status_name' -format to ensure it is clear. -*/ - -var joystickBtn = { - primary_colour: 0x653E, - primary_icon: 'joystick', - primary_text: 'Joystick', - }; - -var turnLeftBtn = { - primary_colour: 0x653E, - primary_text: 'Left', - primary_icon: 'left', - }; - -var turnRightBtn = { - primary_colour: 0x33F9, - primary_text: 'Right', - primary_icon: 'right', - }; - -var tailHBtn = { - primary_colour: 0x653E, - primary_text: 'Wag Tail', - primary_icon: 'wag_h', - }; - -var tailVBtn = { - primary_colour: 0x33F9, - primary_text: 'Wag Tail', - primary_icon: 'wag_v', - }; - -var chessBtn = { - primary_colour: 0xE9C7, - primary_text: 'Off', - primary_icon: 'pawn', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'On', - secondary_icon : 'pawn', - value: status_chess - }; - -var wakeBtn = { - primary_colour: 0xE9C7, - primary_text: 'Sleeping', - primary_icon: 'sleep', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Awake', - secondary_icon : 'awake', - value: status_wake - }; - -var autoBtn = { - primary_colour: 0xE9C7, - primary_text: 'Stop', - primary_icon: 'sit', - toggle: true, - secondary_colour: 0x3F48, - secondary_text: 'Move', - secondary_icon : 'walk', - value: status_auto - }; - -/* -CONFIGURATION AREA - SCREEN DEFINITIONS -a screen can have a button (as defined above) -on the left and/or the right of the screen. -in adddition a screen can optionally have -an icon for each of the three buttons on -the left hand side of the screen. These -are defined as btn1, bt2 and bt3. The -values are names from the icon array. -*/ -const menuScreen = { - left: wakeBtn, - right: joystickBtn, - btn1: "pawn", - btn2: "wag_v", -}; - -const joystickScreen = { - left: turnLeftBtn, - right: turnRightBtn, - btn1: "forward", - btn2: "backward", - btn3: "back" -}; - -const tailScreen = { - left: tailHBtn, - right: tailVBtn, - btn3: "back" -}; - -const chessScreen = { - left: chessBtn, - right: autoBtn, - btn3: "back" -}; - - -/* base state definition -Each of the screens correspond to a state; -this class provides a constuctor for each -of the states -*/ -class State { - constructor(params) { - this.state = params.state; - this.events = params.events; - this.screen = params.screen; - } -} - -/* -CONFIGURATION AREA - BUTTON BEHAVIOURS/STATE TRANSITIONS -This area defines how each screen behaves. -Each screen corresponds to a different State of the -state machine. This makes it much easier to isolate -behaviours between screens. -The state value is transmitted whenever a button is pressed -to provide context (so the receiving device, knows which -button was pressed on which screen). -The screens are defined above. -The events section identifies if a particular button has been -pressed and released on the screen and an action can then be taken. -The events function receives a notification from a mySetWatch which -provides an event object that identifies which button and whether -it has been pressed down or released. Actions can then be taken. -The events function will always return a State object. -If the events function returns different State from the current -one, then the state machine will change to that new State and redrsw -the screen appropriately. -To add in additional capabilities for button presses, simply add -an additional 'if' statement. -For toggle buttons, the value of the appropiate status object is -inversed and the new value transmitted. -*/ - -/* The Home State/Page is where the application beings */ - -const Home = new State({ - state: "K9Menu", - screen: menuScreen, - events: (event) => { - if ((event.object == "top") && (event.status == "end")) { - return Chess; - } - if ((event.object == "middle") && (event.status == "end")) { - return Tail; - } - if ((event.object == "right") && (event.status == "end")) { - return Joystick; - } - if ((event.object == "left") && (event.status == "end")) { - status_wake.value = !status_wake.value; - transmit(this.state, "wake", onOff(status_wake.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Chess = new State({ - state: "Chess", - screen: chessScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - if ((event.object == "right") && (event.status == "end")) { - status_auto.value = !status_auto.value; - transmit(this.state, "follow", onOff(status_auto.value)); - return this; - } - if ((event.object == "left") && (event.status == "end")) { - status_chess.value = !status_chess.value; - transmit(this.state, "chess", onOff(status_chess.value)); - return this; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -const Tail = new State({ - state: "Tail", - screen: tailScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* Joystick page state */ -const Joystick = new State({ - state: "Joystick", - screen: joystickScreen, - events: (event) => { - if ((event.object == "bottom") && (event.status == "end")) { - transmit("Joystick", "joystick", "off"); - return Home; - } - transmit(this.state, event.object, event.status); - return this; - } -}); - -/* translate button status into english */ -const startEnd = status => status ? "start" : "end"; - -/* translate status into english */ -const onOff= status => status ? "on" : "off"; - - -/* create watching functions that will change the global -button status when pressed or released -This is actuslly the hesrt of the program. When a button -is not being pressed, nothing is happening (no loops). -This makes the progrsm more battery efficient. -When a setWatch event is raised, the custom callbacks defined -here will be called. These then fired as events to the current -state/screen of the state mschine. -Some events, will result in the stste of the state machine -chsnging, which is why the screen is redrswn after each -button press. -*/ -const setMyWatch = (params) => { - setWatch(() => { - params.bool=!params.bool; - machine = machine.events({object: params.label, status: startEnd(params.bool)}); - drawScreen(machine.screen); - }, params.btn, {repeat:true, edge:"both"}); -}; - -/* object array used to set up the watching functions -*/ -const buttons = [ - {bool : bottom_btn, label : "bottom",btn : BTN3}, - {bool : middle_btn, label : "middle",btn : BTN2}, - {bool : top_btn, label : "top",btn : BTN1}, - {bool : left_btn, label : "left",btn : BTN4}, - {bool : right_btn, label : "right",btn : BTN5} - ]; - -/* set up watchers for buttons */ -for (var button of buttons) - {setMyWatch(button);} - -/* Draw various kinds of buttons */ -const drawButton = (params,side) => { - g.setFontAlign(0,1); - icon = drawIcon(params.primary_icon); - text = params.primary_text; - g.setColor(params.primary_colour); - const x = (side == "left") ? 0 : 120; - if ((params.toggle) && (params.value.value)) { - g.setColor(params.secondary_colour); - text = params.secondary_text; - icon = drawIcon(params.secondary_icon); - } - g.fillRect(0+x,28,119+x, 239); - g.setColor(0x000); - g.setFont("Vector",15); - g.setFontAlign(0,0.0); - g.drawString(text,60+x,160); - options = {rotate: 0, scale:2}; - g.drawImage(icon,x+60,120,options); -}; - -/* Draw the pages corresponding to the states */ -const drawScreen = (params) => { - drawButton(params.left,'left'); - drawButton(params.right,'right'); - g.setColor(0x000); - if (params.btn1) {g.drawImage(drawIcon(params.btn1),210,40);} - if (params.btn2) {g.drawImage(drawIcon(params.btn2),210,125);} - if (params.btn3) {g.drawImage(drawIcon(params.btn3),210,195);} -}; - -machine = Home; // instantiate the state machine at Home -Bangle.drawWidgets(); // draw active widgets -drawScreen(machine.screen); // draw the screen diff --git a/apps/k9control/k9_icon_30.png b/apps/k9control/k9_icon_30.png deleted file mode 100644 index f8ecae2b85dc24a11aaa4cb4e0dedba20c92e5cd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4779 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 Z9FxZ=hg`FO|9t`gll|tDyZT2@{R^8<=kNdk From 1658b5f035f9141d0a226b6763e900c5404c1589 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Fri, 12 Jun 2020 15:10:08 +0100 Subject: [PATCH 64/72] new pixels --- apps.json | 2 +- apps/about/ChangeLog | 1 + apps/about/app.js | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 7aaf66a13..a09aa6c6b 100644 --- a/apps.json +++ b/apps.json @@ -53,7 +53,7 @@ { "id": "about", "name": "About", "icon": "app.png", - "version":"0.05", + "version":"0.06", "description": "Bangle.js About page - showing software version, stats, and a collaborative mural from the Bangle.js KickStarter backers", "tags": "tool,system", "allow_emulator":true, diff --git a/apps/about/ChangeLog b/apps/about/ChangeLog index 16aea0610..2a050c91e 100644 --- a/apps/about/ChangeLog +++ b/apps/about/ChangeLog @@ -3,3 +3,4 @@ 0.03: Actual pixels as of 5 Mar 2020 0.04: Actual pixels as of 9 Mar 2020 0.05: Actual pixels as of 27 Apr 2020 +0.06: Actual pixels as of 12 Jun 2020 diff --git a/apps/about/app.js b/apps/about/app.js index 57c85563d..4b4589262 100644 --- a/apps/about/app.js +++ b/apps/about/app.js @@ -29,5 +29,5 @@ g.drawString(NRF.getAddress(),120,232); g.flip(); // Pixel chooser image -g.drawImage(require("heatshrink").decompress(atob("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")),0,135); +g.drawImage(require("heatshrink").decompress(atob("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")),0,135); g.flip(); From a1820b7e7ec5f60002567e74ff49c1b4fe7ca66e Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Sat, 13 Jun 2020 08:15:43 +0200 Subject: [PATCH 65/72] Added Mixed Clock 2 fork of original mixed clock Differences to original Mixed Clock: - Color is all white for better readability in the bright sunlight - Thicker clock hands for better readability in the bright sunlight - Extra space under the clock for widgets - Seconds in the digital clock --- apps.json | 13 ++++ apps/miclock2/clock-mixed-icon.js | 1 + apps/miclock2/clock-mixed.js | 113 ++++++++++++++++++++++++++++++ apps/miclock2/clock-mixed.png | Bin 0 -> 707 bytes 4 files changed, 127 insertions(+) create mode 100644 apps/miclock2/clock-mixed-icon.js create mode 100644 apps/miclock2/clock-mixed.js create mode 100755 apps/miclock2/clock-mixed.png diff --git a/apps.json b/apps.json index a09aa6c6b..55d70fe34 100644 --- a/apps.json +++ b/apps.json @@ -1945,5 +1945,18 @@ {"name":"gpspoilog.app.js","url":"app.js"}, {"name":"gpspoilog.img","url":"app-icon.js","evaluate":true} ] + }, + { "id": "miclock2", + "name": "Mixed Clock 2", + "icon": "clock-mixed.png", + "version":"0.01", + "description": "White color variant of the Mixed Clock with thicker clock hands for better readability in the bright sunlight, extra space under the clock for widgets and seconds in the digital clock.", + "tags": "clock", + "type":"clock", + "allow_emulator":true, + "storage": [ + {"name":"miclock.app.js","url":"clock-mixed.js"}, + {"name":"miclock.img","url":"clock-mixed-icon.js","evaluate":true} + ] } ] diff --git a/apps/miclock2/clock-mixed-icon.js b/apps/miclock2/clock-mixed-icon.js new file mode 100644 index 000000000..3ca3b0612 --- /dev/null +++ b/apps/miclock2/clock-mixed-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwxH+AH4A/AH4ATiwAGFdYzlFp4xeFyYwZD49kxGs2fX6+z1mIsgxcDQtAxArCAA+zxFAGDAYFxAsJAAuIGCxcF1omHgEABI+sGCouERRIvJSgKTEFzovLGAJgRCIiMIF5ySGF57qMF5nXsgvORoggLF5yRPLyAvO6+IF6LsKF6JgEF5lkD5gvPYIiOaF6CQMBYesD5oAP1gvPXxpfDAQIAFYCILDJ5wvP64veACCPeAB6PQd4p9EQQ4MLd6GIF7uIF5YwDsgiNAY4vHsguLYBJfXXxiQKL66ONF4lAL7dAF5pgIF6y9DFxYvEi2sF6+sDwgvLGAryEACLsEFxrCGGCmzXh5gJSQYAPRgovQGA1kMR7qEFyQwHi2IGJWzxCLEFygwIMYOI1gzC2esxBbGFywxKABotXGCwuaGKQtdGZorjAH4A/AF4=")) diff --git a/apps/miclock2/clock-mixed.js b/apps/miclock2/clock-mixed.js new file mode 100644 index 000000000..d928a5185 --- /dev/null +++ b/apps/miclock2/clock-mixed.js @@ -0,0 +1,113 @@ +// Code based on the original Mixed Clock + +/* jshint esversion: 6 */ +var locale = require("locale"); +const Radius = { "center": 7, "hour": 60, "min": 80, "dots": 88 }; +const Center = { "x": 120, "y": 96 }; +const Widths = { hour: 2, minute: 2 }; +var buf = Graphics.createArrayBuffer(240,192,1,{msb:true}); + +function rotatePoint(x, y, d) { + rad = -1 * d / 180 * Math.PI; + var sin = Math.sin(rad); + var cos = Math.cos(rad); + xn = ((Center.x + x * cos - y * sin) + 0.5) | 0; + yn = ((Center.y + x * sin - y * cos) + 0.5) | 0; + p = [xn, yn]; + return p; +} + + +// from https://github.com/espruino/Espruino/issues/1702 +function setLineWidth(x1, y1, x2, y2, lw) { + var dx = x2 - x1; + var dy = y2 - y1; + var d = Math.sqrt(dx * dx + dy * dy); + dx = dx * lw / d; + dy = dy * lw / d; + + return [ + // rounding + x1 - (dx + dy) / 2, y1 - (dy - dx) / 2, + x1 - dx, y1 -dy, + x1 + (dy - dx) / 2, y1 - (dx + dy) / 2, + + x1 + dy, y1 - dx, + x2 + dy, y2 - dx, + + // rounding + x2 + (dx + dy) / 2, y2 + (dy - dx) / 2, + x2 + dx, y2 + dy, + x2 - (dy - dx) / 2, y2 + (dx + dy) / 2, + + x2 - dy, y2 + dx, + x1 - dy, y1 + dx + ]; +} + + +function drawMixedClock(force) { + if ((force || Bangle.isLCDOn()) && buf.buffer) { + var date = new Date(); + var dateArray = date.toString().split(" "); + var isEn = locale.name.startsWith("en"); + var point = []; + var minute = date.getMinutes(); + var hour = date.getHours(); + var radius; + + g.reset(); + buf.clear(); + + // draw date + buf.setFont("6x8", 2); + buf.setFontAlign(-1, 0); + buf.drawString(locale.dow(date,true) + ' ', 4, 16, true); + buf.drawString(isEn?(' ' + dateArray[2]):locale.month(date,true), 4, 176, true); + buf.setFontAlign(1, 0); + buf.drawString(isEn?locale.month(date,true):(' ' + dateArray[2]), 237, 16, true); + buf.drawString(dateArray[3], 237, 176, true); + + // draw hour and minute dots + for (i = 0; i < 60; i++) { + radius = (i % 5) ? 2 : 4; + point = rotatePoint(0, Radius.dots, i * 6); + buf.fillCircle(point[0], point[1], radius); + } + + // draw digital time + buf.setFont("6x8", 3); + buf.setFontAlign(0, 0); + buf.drawString(dateArray[4], 120, 120, true); + + // draw new minute hand + point = rotatePoint(0, Radius.min, minute * 6); + buf.drawLine(Center.x, Center.y, point[0], point[1]); + buf.fillPoly(setLineWidth(Center.x, Center.y, point[0], point[1], Widths.minute)); + // draw new hour hand + point = rotatePoint(0, Radius.hour, hour % 12 * 30 + date.getMinutes() / 2 | 0); + buf.fillPoly(setLineWidth(Center.x, Center.y, point[0], point[1], Widths.hour)); + + // draw center + buf.fillCircle(Center.x, Center.y, Radius.center); + + g.drawImage({width:buf.getWidth(),height:buf.getHeight(),bpp:1,buffer:buf.buffer},0,24); + } +} + +Bangle.on('lcdPower', function(on) { + if (on) + drawMixedClock(true); + Bangle.drawWidgets(); +}); + +setInterval(() => drawMixedClock(true), 30000); // force an update every 30s even screen is off + +g.clear(); +Bangle.loadWidgets(); +Bangle.drawWidgets(); +drawMixedClock(); // immediately draw +setInterval(drawMixedClock, 500); // update twice a second + +// Show launcher when middle button pressed after freeing memory first +setWatch(() => {delete buf.buffer; Bangle.showLauncher()}, BTN2, {repeat:false,edge:"falling"}); diff --git a/apps/miclock2/clock-mixed.png b/apps/miclock2/clock-mixed.png new file mode 100755 index 0000000000000000000000000000000000000000..f02ad5e9ee3a0bf215beed0d8cf9d8765015b314 GIT binary patch literal 707 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sa{_!qT!A#h<|7Pi4ua5HFbQJp zXIKqmL!}Nu)d0C0Pcy7Jz_11^0@Skh5J>T=0}N|{f(PHddk0d?KpYl@w4E=7yS=i zxccJNmV1x&cAi=$dl2LS>5?G7UISE7D(w3b_%UOgE( z!JUDDakr<7V~EG`yP-FyH5u@PGO{{49xq+BhH24`GiUz)zdd0UuRzrOz0Y4P%*~r^ z^3wOc^2PfW$F^^ch$ue%@mKy?_tOv8wJo#`nl<}Y!u3NA#!tV+Ut7og%jMagZw4Ro zD+SXcBV3mLpK;O3d1mj=M~eJ2945&Bcv5j~qy6^p{*u`W)<5Ssp1<(p+x6)W>;C`p z3VJ8nDW3M<$&K?(MdQ}6C(HPLH`@wLU`&6ZR(N8+k=Fwa1-{)A<4;`gJjwBfM{>>c z8cx2{A}0pFom;hAf1Q+6R8U%>z2_FMi@*vFMwf@2O~Ji+KCTI=sgF3C8s!3+ex-06 z+9M_U_34bQ6GPO39UE5ho#gzj{==f>4kuHJVwiB!2^Pf@jV!N(Sa-QJv#~!|Z+c+C z$0%h{#`U7Y;n#AH_zS$7dNNADCQfRTuuEo+=SNS!1CN9YDl1R>cR1RFJz@0Zc*HnS zebxyM&iX|mESHpDAK~wE@J`d4(r9#9Gv%fJEz{OB%YrfsR@$(yU1ZI@a!N;`)YYRF zPKIG8Y9&<@W!gPU>QC*}eH|kldpAJCXZALo+aczz+i!}5FaDl;y|`zksYFC@^4_=K b?F9c{ecS$I?dMmTpw#H;>gTe~DWM4f>^e@f literal 0 HcmV?d00001 From 687db8904f37410462d22b23fc12ce4d942a87fa Mon Sep 17 00:00:00 2001 From: Erik Andresen Date: Sat, 13 Jun 2020 08:25:48 +0200 Subject: [PATCH 66/72] Mixed Clock 2: Fix apps.json entry --- apps.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps.json b/apps.json index 55d70fe34..6c7ede88f 100644 --- a/apps.json +++ b/apps.json @@ -1955,8 +1955,8 @@ "type":"clock", "allow_emulator":true, "storage": [ - {"name":"miclock.app.js","url":"clock-mixed.js"}, - {"name":"miclock.img","url":"clock-mixed-icon.js","evaluate":true} + {"name":"miclock2.app.js","url":"clock-mixed.js"}, + {"name":"miclock2.img","url":"clock-mixed-icon.js","evaluate":true} ] } ] From 3404d244b66735cecfeaa91ea8d6be4289744d1b Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Sat, 13 Jun 2020 16:29:17 -0400 Subject: [PATCH 67/72] App Manager: reduce memory usage --- apps.json | 2 +- apps/files/ChangeLog | 1 + apps/files/files.js | 29 ++++++++++++++--------------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps.json b/apps.json index a09aa6c6b..2cddea678 100644 --- a/apps.json +++ b/apps.json @@ -403,7 +403,7 @@ { "id": "files", "name": "App Manager", "icon": "files.png", - "version":"0.05", + "version":"0.06", "description": "Show currently installed apps, free space, and allow their deletion from the watch", "tags": "tool,system,files", "storage": [ diff --git a/apps/files/ChangeLog b/apps/files/ChangeLog index f2e5f64f5..b4037a733 100644 --- a/apps/files/ChangeLog +++ b/apps/files/ChangeLog @@ -2,3 +2,4 @@ 0.03: Add support for data files 0.04: Add functionality to sort apps manually or alphabetically ascending/descending. 0.05: Tweaks to help with memory usage +0.06: Reduce memory usage \ No newline at end of file diff --git a/apps/files/files.js b/apps/files/files.js index ab259d6df..e240a8e68 100644 --- a/apps/files/files.js +++ b/apps/files/files.js @@ -45,13 +45,13 @@ function globToRegex(pattern) { return new RegExp('^'+regex+'$'); } -function eraseFiles(app) { - app.files.split(",").forEach(f=>store.erase(f)); +function eraseFiles(info) { + info.files.split(",").forEach(f=>store.erase(f)); } -function eraseData(app) { - if(!app.data) return; - const d=app.data.split(';'), +function eraseData(info) { + if(!info.data) return; + const d=info.data.split(';'), files=d[0].split(','), sFiles=(d[1]||'').split(','); let erase = f=>store.erase(f); @@ -68,8 +68,9 @@ function eraseData(app) { } function eraseApp(app, files,data) { E.showMessage('Erasing\n' + app.name + '...'); - if (files) eraseFiles(app); - if (data) eraseData(app); + var info = store.readJSON(app.id + ".info", 1)||{}; + if (files) eraseFiles(info); + if (data) eraseData(info); } function eraseOne(app, files,data){ E.showPrompt('Erase\n'+app.name+'?').then((v) => { @@ -86,8 +87,7 @@ function eraseAll(apps, files,data) { E.showPrompt('Erase all?').then((v) => { if (v) { Bangle.buzz(100, 1); - for(var n = 0; n eraseApp(app, files, data)); } showApps(); }); @@ -100,7 +100,7 @@ function showAppMenu(app) { }, '< Back': () => showApps(), }; - if (app.data) { + if (app.hasData) { appmenu['Erase Completely'] = () => eraseOne(app, true, true); appmenu['Erase App,Keep Data'] = () => eraseOne(app, true, false); appmenu['Only Erase Data'] = () => eraseOne(app, false, true); @@ -120,11 +120,10 @@ function showApps() { var list = store.list(/\.info$/).filter((a)=> { return a !== 'setting.info'; - }).sort().map((app) => { - var ret = store.readJSON(app,1)||{}; - ret[''] = app; - return ret; - }); + }).map((a)=> { + let app = store.readJSON(a, 1) || {}; + return {id: app.id, name: app.name, hasData: !!app.data}; + }).sort(sortHelper());; if (list.length > 0) { list.reduce((menu, app) => { From 30864632a626dc66c7f41bd0d6993f640f6055a2 Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Sat, 13 Jun 2020 17:10:42 -0400 Subject: [PATCH 68/72] largeclock: Adjust layout to account for new font --- apps.json | 2 +- apps/largeclock/ChangeLog | 1 + apps/largeclock/largeclock.js | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index a09aa6c6b..563e7fd70 100644 --- a/apps.json +++ b/apps.json @@ -1605,7 +1605,7 @@ "id": "largeclock", "name": "Large Clock", "icon": "largeclock.png", - "version": "0.03", + "version": "0.04", "description": "A readable and informational digital watch, with date, seconds and moon phase", "readme": "README.md", "tags": "clock", diff --git a/apps/largeclock/ChangeLog b/apps/largeclock/ChangeLog index fe44e5078..15dcd269e 100644 --- a/apps/largeclock/ChangeLog +++ b/apps/largeclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: Init 0.02: fix 3/4 moon orientation 0.03: Change `largeclock.json` to 'data' file to allow settings to be preserved +0.04: Adjust layout to account for new vector font diff --git a/apps/largeclock/largeclock.js b/apps/largeclock/largeclock.js index 9975775fb..913040557 100644 --- a/apps/largeclock/largeclock.js +++ b/apps/largeclock/largeclock.js @@ -8,7 +8,7 @@ const moonR = 12; const moonX = 215; const moonY = 50; -const settings = require("Storage").readJSON("largeclock.json", 1); +const settings = require("Storage").readJSON("largeclock.json", 1)||{}; const BTN1app = settings.BTN1 || ""; const BTN3app = settings.BTN3 || ""; @@ -131,12 +131,12 @@ function drawTime(d) { g.setColor(1, 1, 1); g.setFontAlign(-1, -1); g.setFont("Vector", 100); - g.drawString(hours, 50, 24, true); + g.drawString(hours, 40, 24, true); g.setColor(1, 50, 1); - g.drawString(minutes, 50, 135, true); + g.drawString(minutes, 40, 135, true); g.setFont("Vector", 20); g.setRotation(3); - g.drawString(`${dow} ${day} ${month}`, 50, 15, true); + g.drawString(`${dow} ${day} ${month}`, 50, 10, true); g.drawString(year, 75, 205, true); lastMinutes = minutes; } @@ -144,7 +144,7 @@ function drawTime(d) { g.setFont("Vector", 20); g.setColor(1, 1, 1); g.setFontAlign(0, -1); - g.clearRect(200, 210, 240, 240); + g.clearRect(195, 210, 240, 240); g.drawString(seconds, 215, 215); } From 86bb7da3524a3266fe86f1d2a88387f3978bda43 Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Sat, 13 Jun 2020 17:49:45 -0400 Subject: [PATCH 69/72] largeclock: Support 12 hour time --- apps.json | 2 +- apps/largeclock/ChangeLog | 1 + apps/largeclock/largeclock.js | 20 +++++++++++++++----- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index 563e7fd70..ec757c96e 100644 --- a/apps.json +++ b/apps.json @@ -1605,7 +1605,7 @@ "id": "largeclock", "name": "Large Clock", "icon": "largeclock.png", - "version": "0.04", + "version": "0.05", "description": "A readable and informational digital watch, with date, seconds and moon phase", "readme": "README.md", "tags": "clock", diff --git a/apps/largeclock/ChangeLog b/apps/largeclock/ChangeLog index 15dcd269e..494002e0e 100644 --- a/apps/largeclock/ChangeLog +++ b/apps/largeclock/ChangeLog @@ -2,3 +2,4 @@ 0.02: fix 3/4 moon orientation 0.03: Change `largeclock.json` to 'data' file to allow settings to be preserved 0.04: Adjust layout to account for new vector font +0.05: Add support for 12 hour time \ No newline at end of file diff --git a/apps/largeclock/largeclock.js b/apps/largeclock/largeclock.js index 913040557..6f3d638fa 100644 --- a/apps/largeclock/largeclock.js +++ b/apps/largeclock/largeclock.js @@ -4,9 +4,11 @@ let interval; let lastMoonPhase; let lastMinutes; +const is12Hour = (require("Storage").readJSON("setting.json",1)||{})["12hour"]; + const moonR = 12; const moonX = 215; -const moonY = 50; +const moonY = is12Hour ? 90 : 50; const settings = require("Storage").readJSON("largeclock.json", 1)||{}; const BTN1app = settings.BTN1 || ""; @@ -118,15 +120,23 @@ function drawMoon(d) { function drawTime(d) { const da = d.toString().split(" "); - const time = da[4].substr(0, 5).split(":"); + const time = da[4].split(":"); const dow = da[0]; const month = da[1]; const day = da[2]; const year = da[3]; - const hours = time[0]; + const hours = is12Hour ? ("0" + (((d.getHours() + 11) % 12) + 1)).substr(-2) : time[0]; + const meridian = d.getHours() < 12 ? "AM" : "PM"; const minutes = time[1]; - const seconds = d.getSeconds(); + const seconds = time[2]; if (minutes != lastMinutes) { + if (is12Hour) { + g.setFont("Vector", 18); + g.setColor(1, 1, 1); + g.setFontAlign(0, -1); + g.clearRect(195, 34, 240, 44); + g.drawString(meridian, 217, 34); + } g.clearRect(0, 24, moonX - moonR - 10, 239); g.setColor(1, 1, 1); g.setFontAlign(-1, -1); @@ -137,7 +147,7 @@ function drawTime(d) { g.setFont("Vector", 20); g.setRotation(3); g.drawString(`${dow} ${day} ${month}`, 50, 10, true); - g.drawString(year, 75, 205, true); + g.drawString(year, is12Hour ? 46 : 75, 205, true); lastMinutes = minutes; } g.setRotation(0); From 5805329248b80518f01f4272c0285102f16018ed Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Sat, 13 Jun 2020 21:20:47 -0400 Subject: [PATCH 70/72] blobclk: Adapt to fillPoly changes --- apps.json | 2 +- apps/blobclk/ChangeLog | 1 + apps/blobclk/clock-blob.js | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps.json b/apps.json index a09aa6c6b..ab08ea051 100644 --- a/apps.json +++ b/apps.json @@ -869,7 +869,7 @@ "name": "Large Digit Blob Clock", "shortName" : "Blob Clock", "icon": "clock-blob.png", - "version":"0.03", + "version":"0.04", "description": "A clock with big digits", "tags": "clock", "type":"clock", diff --git a/apps/blobclk/ChangeLog b/apps/blobclk/ChangeLog index 1cfc59015..9715fc4ab 100644 --- a/apps/blobclk/ChangeLog +++ b/apps/blobclk/ChangeLog @@ -2,3 +2,4 @@ Only draw widgets after clearing screen - they update automatically Remove 'faceUp' check as it's automatic 0.03: Modified for use with new bootloader and firmware +0.04: Modified to account for changes in the behavior of Graphics.fillPoly diff --git a/apps/blobclk/clock-blob.js b/apps/blobclk/clock-blob.js index 1d85bc65e..76f10865f 100644 --- a/apps/blobclk/clock-blob.js +++ b/apps/blobclk/clock-blob.js @@ -18,8 +18,8 @@ function flip() { g.drawImage({width:buf.getWidth(),height:buf.getHeight(),buffer:buf.buffer},55,26); } function drawPixel(ox,oy,x,y,r,p) { - let x1 = ox+x*(r*2+1); - let y1 = oy+y*(r*2+1); + let x1 = ox+x*(r*2); + let y1 = oy+y*(r*2); let xmid = x1+r; let ymid = y1+r; let x2 = xmid+r; @@ -27,14 +27,14 @@ function drawPixel(ox,oy,x,y,r,p) { if (p > 0) { if (p > 1) { buf.setColor(0,0,0); - buf.fillRect(x1,y1,x2,y2); + buf.fillPoly([x1,y1,x2,y1,x2,y2,x1,y2]); } buf.setColor(1,1,1); } else { buf.setColor(0,0,0); } if (p < 2) { - buf.fillRect(x1,y1,x2,y2); + buf.fillPoly([x1,y1,x2,y1,x2,y2,x1,y2]); } else if (p === 2) { buf.fillPoly([xmid,y1,x2,y1,x2,y2,x1,y2,x1,ymid]); } else if (p === 3) { From 36e1b6b61e02789bf33722bb4d7233a5e6022829 Mon Sep 17 00:00:00 2001 From: Ben Whittaker Date: Sat, 13 Jun 2020 21:27:54 -0400 Subject: [PATCH 71/72] App Manager: remove extra semicolon --- apps/files/files.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/files.js b/apps/files/files.js index e240a8e68..9e6c97702 100644 --- a/apps/files/files.js +++ b/apps/files/files.js @@ -123,7 +123,7 @@ function showApps() { }).map((a)=> { let app = store.readJSON(a, 1) || {}; return {id: app.id, name: app.name, hasData: !!app.data}; - }).sort(sortHelper());; + }).sort(sortHelper()); if (list.length > 0) { list.reduce((menu, app) => { From 2ffdd2d2829417572b102280b2ee3d7570dba418 Mon Sep 17 00:00:00 2001 From: Francesco Bedussi Date: Sun, 14 Jun 2020 16:15:59 +0200 Subject: [PATCH 72/72] feat: allow to disable BTN1 and BTN3 buttons --- apps.json | 2 +- apps/largeclock/ChangeLog | 1 + apps/largeclock/README.md | 2 +- apps/largeclock/largeclock.js | 4 ++-- apps/largeclock/largeclock.json | 4 ++-- apps/largeclock/settings.js | 4 ++++ 6 files changed, 11 insertions(+), 6 deletions(-) diff --git a/apps.json b/apps.json index a09aa6c6b..563e7fd70 100644 --- a/apps.json +++ b/apps.json @@ -1605,7 +1605,7 @@ "id": "largeclock", "name": "Large Clock", "icon": "largeclock.png", - "version": "0.03", + "version": "0.04", "description": "A readable and informational digital watch, with date, seconds and moon phase", "readme": "README.md", "tags": "clock", diff --git a/apps/largeclock/ChangeLog b/apps/largeclock/ChangeLog index fe44e5078..39ab5d629 100644 --- a/apps/largeclock/ChangeLog +++ b/apps/largeclock/ChangeLog @@ -1,3 +1,4 @@ 0.01: Init 0.02: fix 3/4 moon orientation 0.03: Change `largeclock.json` to 'data' file to allow settings to be preserved +0.04: Allow to disable BTN1 and BTN3 buttons diff --git a/apps/largeclock/README.md b/apps/largeclock/README.md index c9a325823..5c2ad42c2 100644 --- a/apps/largeclock/README.md +++ b/apps/largeclock/README.md @@ -11,7 +11,7 @@ A readable and informational digital watch, with date, seconds and moon phase an ## How to use it - The clock can be used as any other one, if you like it just set it as the default clock app in settings > select clock -- In setting > large clock you can select which app is to be open by BTN1 and BTN3 +- In setting > large clock you can select which app, if any, is to be open by BTN1 and BTN3 ## Credits diff --git a/apps/largeclock/largeclock.js b/apps/largeclock/largeclock.js index 9975775fb..fb4835146 100644 --- a/apps/largeclock/largeclock.js +++ b/apps/largeclock/largeclock.js @@ -9,8 +9,8 @@ const moonX = 215; const moonY = 50; const settings = require("Storage").readJSON("largeclock.json", 1); -const BTN1app = settings.BTN1 || ""; -const BTN3app = settings.BTN3 || ""; +const BTN1app = settings && settings.BTN1 || ""; +const BTN3app = settings && settings.BTN3 || ""; function drawMoon(d) { const BLACK = 0, diff --git a/apps/largeclock/largeclock.json b/apps/largeclock/largeclock.json index 7c38d59de..58c981197 100644 --- a/apps/largeclock/largeclock.json +++ b/apps/largeclock/largeclock.json @@ -1,4 +1,4 @@ { - "BTN1": "timer.app.js", - "BTN3": "calendar.app.js" + "BTN1": "", + "BTN3": "" } diff --git a/apps/largeclock/settings.js b/apps/largeclock/settings.js index a33f3c438..293f66677 100644 --- a/apps/largeclock/settings.js +++ b/apps/largeclock/settings.js @@ -21,6 +21,10 @@ if (a.n > b.n) return 1; return 0; }); + apps.push({ + n: "NONE", + src: "" + }); const settings = s.readJSON("largeclock.json", 1) || { BTN1: "",