Merge branch 'upstream/master' into fix/improve-formatter-check

master
Rob Pilling 2024-02-05 22:30:31 +00:00
commit b2ff9dbb78
24 changed files with 461 additions and 281 deletions

View File

@ -1 +1 @@
0.01: New Widget!
0.01: New Clock Info!

View File

@ -0,0 +1 @@
0.01: New Clock!

View File

@ -0,0 +1,25 @@
# Clock Name
More info on making Clock Faces: https://www.espruino.com/Bangle.js+Clock
Describe the Clock...
## Usage
Describe how to use it
## Features
Name the function
## Controls
Name the buttons and what they are used for
## Requests
Name who should be contacted for support/update requests
## Creator
Your name

View File

@ -0,0 +1 @@
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))

View File

@ -0,0 +1,44 @@
// timeout used to update every minute
var drawTimeout;
// schedule a draw for the next minute
function queueDraw() {
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function() {
drawTimeout = undefined;
draw();
}, 60000 - (Date.now() % 60000));
}
function draw() {
// queue next draw in one minute
queueDraw();
// Work out where to draw...
var x = g.getWidth()/2;
var y = g.getHeight()/2;
g.reset();
// work out locale-friendly date/time
var date = new Date();
var timeStr = require("locale").time(date,1);
var dateStr = require("locale").date(date);
// draw time
g.setFontAlign(0,0).setFont("Vector",48);
g.clearRect(0,y-15,g.getWidth(),y+25); // clear the background
g.drawString(timeStr,x,y);
// draw date
y += 35;
g.setFontAlign(0,0).setFont("6x8");
g.clearRect(0,y-4,g.getWidth(),y+4); // clear the background
g.drawString(dateStr,x,y);
}
// Clear the screen once, at startup
g.clear();
// draw immediately at first, queue update
draw();
// Show launcher when middle button pressed
Bangle.setUI("clock");
// Load widgets
Bangle.loadWidgets();
Bangle.drawWidgets();

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,15 @@
{ "id": "7chname",
"name": "My clock human readable name",
"shortName":"Short Name",
"version":"0.01",
"description": "A detailed description of my clock",
"icon": "icon.png",
"type": "clock",
"tags": "clock",
"supports" : ["BANGLEJS2"],
"readme": "README.md",
"storage": [
{"name":"7chname.app.js","url":"app.js"},
{"name":"7chname.img","url":"app-icon.js","evaluate":true}
]
}

View File

@ -32,3 +32,4 @@
Allow alarm enable/disable
0.31: Implement API for activity fetching
0.32: Added support for loyalty cards from gadgetbridge
0.33: Fix alarms created in Gadgetbridge not repeating

View File

@ -81,7 +81,12 @@
for (var j = 0; j < event.d.length; j++) {
// prevents all alarms from going off at once??
var dow = event.d[j].rep;
if (!dow) dow = 127; //if no DOW selected, set alarm to all DOW
var rp = false;
if (!dow) {
dow = 127; //if no DOW selected, set alarm to all DOW
} else {
rp = true;
}
var last = (event.d[j].h * 3600000 + event.d[j].m * 60000 < currentTime) ? (new Date()).getDate() : 0;
var a = require("sched").newDefaultAlarm();
a.id = "gb"+j;
@ -89,6 +94,7 @@
a.on = event.d[j].on !== undefined ? event.d[j].on : true;
a.t = event.d[j].h * 3600000 + event.d[j].m * 60000;
a.dow = ((dow&63)<<1) | (dow>>6); // Gadgetbridge sends DOW in a different format
a.rp = rp;
a.last = last;
alarms.push(a);
}

View File

@ -2,7 +2,7 @@
"id": "android",
"name": "Android Integration",
"shortName": "Android",
"version": "0.32",
"version": "0.33",
"description": "Display notifications/music/etc sent from the Gadgetbridge app on Android. This replaces the old 'Gadgetbridge' Bangle.js widget.",
"icon": "app.png",
"tags": "tool,system,messages,notifications,gadgetbridge",

View File

@ -2,7 +2,7 @@
"name": "BTHome Temperature and Pressure",
"shortName":"BTHome T",
"version":"0.02",
"description": "Displays temperature and pressure, and advertises them over bluetooth using BTHome.io standard",
"description": "Displays temperature and pressure, and advertises them over bluetooth for Home Assistant using BTHome.io standard",
"icon": "app.png",
"tags": "bthome,bluetooth,temperature",
"supports" : ["BANGLEJS2"],

View File

@ -2,7 +2,7 @@
"id": "ha",
"name": "Home Assistant",
"version": "0.10",
"description": "Integrates your Bangle.js into Home Assistant.",
"description": "Integrates your Bangle.js into Home Assistant using Android Integration/Gadgetbridge",
"icon": "ha.png",
"type": "app",
"tags": "tool,clkinfo,bluetooth",

View File

@ -3,7 +3,7 @@
"name": "Home Assistant Sensors",
"shortName": "HA sensors",
"version": "0.02",
"description": "Send sensor values to Home Assistant using the Android Integration.",
"description": "Send sensor values to Home Assistant using Android Integration/Gadgetbridge",
"icon": "ha.png",
"type": "bootloader",
"tags": "tool,sensors",

View File

@ -1 +1,2 @@
0.01: New App!
0.02: Add more control styles

View File

@ -10,8 +10,21 @@ in the future this app will be able to support other types of remote (see below)
## Usage
Run the app, and ensure you're not connected to your watch via Bluetooth
(a warning will pop up if so).
Run the app, then choose the type of controls you want and ensure you're not connected
to your watch via Bluetooth (a warning will pop up if so).
Linear mode controls A/B axes individually, and allows you to vary the speed of the
motors based on the distance you drag from the centre. Other modes just use on/off
buttons.
| Mode | up | down | left | right |
|------------|------|------|------|-------|
| **Linear** | +A | -A | -B | +B |
| **Normal** | +A | -A | -B | +B |
| **Tank** | -A+B | +A-B | +A+B | -A-B |
| **Merged** | -A-B | +A+B | +A-B | -A+B |
In all cases pressing the C/D buttons will turn on C/D outputs
Now press the arrow keys on the screen to control the robot.

View File

@ -1,5 +1,4 @@
var lego = require("mouldking");
lego.start();
E.on('kill', () => {
// return to normal Bluetooth advertising
NRF.setAdvertising({},{showName:true});
@ -12,15 +11,17 @@ var controlState = "";
Bangle.loadWidgets();
Bangle.drawWidgets();
var R = Bangle.appRect;
// we'll divide up into 3x3
function getBoxCoords(x,y) {
function startLegoButtons(controls) {
// we'll divide up into 3x3
function getBoxCoords(x,y) {
return {
x : R.x + R.w*x/3,
y : R.y + R.h*y/3
};
}
}
function draw() {
function draw() {
g.reset().clearRect(R);
var c, ninety = Math.PI/2;
var colOn = "#f00", colOff = g.theme.fg;
@ -36,24 +37,24 @@ function draw() {
c = getBoxCoords(1.5, 2.5);
g.setFontAlign(0,0).setFont("6x8").drawString("WARNING:\nBluetooth Connected\nYou must disconnect\nbefore LEGO will work",c.x,c.y);
}
}
draw();
NRF.on('connect', draw);
NRF.on('disconnect', draw);
g.setFont("6x8:3").setFontAlign(0,0);
c = getBoxCoords(0.5, 0.5);
g.setColor(controlState=="c"?colOn:colOff).drawString("C",c.x,c.y);
c = getBoxCoords(2.5, 0.5);
g.setColor(controlState=="d"?colOn:colOff).drawString("D",c.x,c.y);
}
function setControlState(s) {
function setControlState(s) {
controlState = s;
var c = {};
var speed = 3;
if (s=="up") c={a:-speed,b:-speed};
if (s=="down") c={a:speed,b:speed};
if (s=="left") c={a:speed,b:-speed};
if (s=="right") c={a:-speed,b:speed};
if (s in controls)
c = controls[s];
draw();
lego.set(c);
}
}
Bangle.on('drag',e => {
lego.start();
Bangle.setUI({mode:"custom", drag : e => {
var x = Math.floor(E.clip((e.x - R.x) * 3 / R.w,0,2.99));
var y = Math.floor(E.clip((e.y - R.y) * 3 / R.h,0,2.99));
if (!e.b) {
@ -61,10 +62,82 @@ Bangle.on('drag',e => {
return;
}
if (y==0) { // top row
if (x==0) setControlState("c");
if (x==1) setControlState("up");
if (x==2) setControlState("d");
} else if (y==1) {
if (x==0) setControlState("left");
if (x==1) setControlState("down");
if (x==2) setControlState("right");
}
}});
draw();
NRF.on('connect', draw);
NRF.on('disconnect', draw);
}
function startLegoLinear() {
var mx = R.x+R.w/2;
var my = R.y+R.h/2;
var x=0,y=0;
var scale = 10;
function draw() {
g.reset().clearRect(R);
for (var i=3;i<60;i+=10)
g.drawCircle(mx,my,i);
g.setColor("#F00");
var px = E.clip(mx + x*scale, R.x+20, R.x2-20);
var py = E.clip(my + y*scale, R.y+20, R.y2-20);
g.fillCircle(px, py, 20);
}
lego.start();
Bangle.setUI({mode:"custom", drag : e => {
x = Math.round((e.x - mx) / scale);
y = Math.round((e.y - my) / scale);
if (!e.b) {
x=0; y=0;
}
lego.set({a:x, b:y});
draw();
}});
draw();
NRF.on('connect', draw);
NRF.on('disconnect', draw);
}
// Mappings of button to output
const CONTROLS = {
normal : {
up : {a: 7,b: 0},
down : {a:-7,b: 0},
left : {a: 0,b:-7},
right: {a: 0,b: 7},
c : {c:7},
d : {d:7}
}, tank : {
up : {a:-7,b:7},
down : {a: 7,b:-7},
left : {a: 7,b:7},
right: {a:-7,b:-7},
c : {c:7},
d : {d:7}
}, merged : {
up : {a: 7,b: 7},
down : {a:-7,b:-7},
left : {a: 7,b:-7},
right: {a:-7,b: 7},
c : {c:7},
d : {d:7}
}
};
E.showMenu({ "" : {title:"LEGO Remote", back:()=>load()},
"Linear" : () => startLegoLinear(),
"Normal" : () => startLego(CONTROLS.normal),
"Tank" : () => startLego(CONTROLS.tank),
"Marged" : () => startLego(CONTROLS.merged),
});

View File

@ -1,7 +1,7 @@
{ "id": "legoremote",
"name": "LEGO Remote control",
"shortName":"LEGO Remote",
"version":"0.01",
"version":"0.02",
"description": "Use your Bangle.js to control LEGO models. See the README for compatibility",
"icon": "app.png",
"tags": "toy,lego,bluetooth",

View File

@ -33,3 +33,5 @@
0.26: Ensure that when redrawing, we always cancel any in-progress track draw
0.27: Display message if no map is installed
0.28: Fix rounding errors
0.29: Keep exit at bottom of menu
Speed up latLonToXY for track rendering

View File

@ -172,7 +172,6 @@ function showMenu() {
var menu = {
"":{title:/*LANG*/"Map"},
"< Back": ()=> showMap(),
/*LANG*/"Exit": () => load(),
};
// If we have a GPS fix, add a menu item to center it
if (fix.fix) menu[/*LANG*/"Center GPS"]=() =>{
@ -180,7 +179,6 @@ function showMenu() {
m.lon = fix.lon;
showMap();
};
menu = Object.assign(menu, {
/*LANG*/"Zoom In": () =>{
m.scale /= 2;
@ -234,6 +232,7 @@ function showMenu() {
}
};
}
menu[/*LANG*/"Exit"] = () => load();
E.showMenu(menu);
}

View File

@ -2,7 +2,7 @@
"id": "openstmap",
"name": "OpenStreetMap",
"shortName": "OpenStMap",
"version": "0.28",
"version": "0.29",
"description": "Loads map tiles from OpenStreetMap onto your Bangle.js and displays a map of where you are. Once installed this also adds map functionality to `GPS Recorder` and `Recorder` apps",
"readme": "README.md",
"icon": "app.png",

View File

@ -38,17 +38,17 @@ if (m.map) {
m.lat = m.map.lat; // position of middle of screen
m.lon = m.map.lon; // position of middle of screen
}
var CX = g.getWidth()/2;
var CY = g.getHeight()/2;
// return number of tiles drawn
exports.draw = function() {
var cx = g.getWidth()/2;
var cy = g.getHeight()/2;
var p = Bangle.project({lat:m.lat,lon:m.lon});
let count = 0;
m.maps.forEach((map,idx) => {
var d = map.scale/m.scale;
var ix = (p.x-map.center.x)/m.scale + (map.imgx*d/2) - cx;
var iy = (map.center.y-p.y)/m.scale + (map.imgy*d/2) - cy;
var ix = (p.x-map.center.x)/m.scale + (map.imgx*d/2) - CX;
var iy = (map.center.y-p.y)/m.scale + (map.imgy*d/2) - CY;
var o = {};
var s = map.tilesize;
if (d!=1) { // if the two are different, add scaling
@ -85,14 +85,12 @@ exports.draw = function() {
};
/// Convert lat/lon to pixels on the screen
exports.latLonToXY = function(lat, lon) {
var p = Bangle.project({lat:m.lat,lon:m.lon});
var q = Bangle.project({lat:lat, lon:lon});
var cx = g.getWidth()/2;
var cy = g.getHeight()/2;
exports.latLonToXY = function(lat, lon) { "ram"
var p = Bangle.project({lat:m.lat,lon:m.lon}),
q = Bangle.project({lat:lat, lon:lon});
return {
x : Math.round((q.x-p.x)/m.scale + cx),
y : Math.round(cy - (q.y-p.y)/m.scale)
x : Math.round((q.x-p.x)/m.scale + CX),
y : Math.round(CY - (q.y-p.y)/m.scale)
};
};

View File

@ -45,3 +45,4 @@
0.36: When recording with 1 second periods, log time with one decimal.
0.37: 1 second periods + gps log => log when gps event is received, not with
setInterval.
0.38: Tweaks to speed up track rendering

View File

@ -213,8 +213,10 @@ function viewTrack(filename, info) {
});
};
menu['< Back'] = () => { viewTracks(); };
return E.showMenu(menu);
}
function plotTrack(info) { "ram"
function plotTrack(info) { "ram"
function distance(lat1,long1,lat2,long2) { "ram"
var x = (long1-long2) * Math.cos((lat1+lat2)*Math.PI/360);
var y = lat2 - lat1;
@ -222,7 +224,7 @@ function viewTrack(filename, info) {
}
// Function to convert lat/lon to XY
var getMapXY;
var XY;
if (info.qOSTM) {
// scale map to view full track
const max = Bangle.project({lat: info.maxLat, lon: info.maxLong});
@ -230,9 +232,9 @@ function viewTrack(filename, info) {
const scaleX = (max.x-min.x)/Bangle.appRect.w;
const scaleY = (max.y-min.y)/Bangle.appRect.h;
osm.scale = Math.ceil((scaleX > scaleY ? scaleX : scaleY)*1.1); // add 10% margin
getMapXY = osm.latLonToXY.bind(osm);
XY = osm.latLonToXY.bind(osm);
} else {
getMapXY = function(lat, lon) { "ram"
XY = function(lat, lon) { "ram"
return {x:cx + Math.round((long - info.lon)*info.lfactor*info.scale),
y:cy + Math.round((info.lat - lat)*info.scale)};
};
@ -243,6 +245,7 @@ function viewTrack(filename, info) {
g.flip(); // on buffered screens, draw a not saying we're busy
g.clear(1);
var s = require("Storage");
var G = g;
var W = g.getWidth();
var H = g.getHeight();
var cx = W/2;
@ -275,7 +278,7 @@ function viewTrack(filename, info) {
// now start plotting
var lat = +c[latIdx];
var long = +c[lonIdx];
var mp = getMapXY(lat, long);
var mp = XY(lat, long);
g.moveTo(mp.x,mp.y);
g.setColor("#0f0");
g.fillCircle(mp.x,mp.y,5);
@ -288,16 +291,16 @@ function viewTrack(filename, info) {
if (c[latIdx]=="")continue;
lat = +c[latIdx];
long = +c[lonIdx];
mp = getMapXY(lat, long);
g.lineTo(mp.x,mp.y);
if (info.qOSTM) g.fillCircle(mp.x,mp.y,2); // make the track more visible
mp = XY(lat, long);
G.lineTo(mp.x,mp.y);
if (info.qOSTM) G.fillCircle(mp.x,mp.y,2); // make the track more visible
var d = distance(olat,olong,lat,long);
if (!isNaN(d)) dist+=d;
olat = lat;
olong = long;
ox = mp.x;
oy = mp.y;
if (++i > 100) { g.flip();i=0; }
if (++i > 100) { G.flip();i=0; }
}
g.setColor("#f00");
g.fillCircle(ox,oy,5);
@ -313,9 +316,9 @@ function viewTrack(filename, info) {
}, isBTN3?BTN3:BTN1);
Bangle.drawWidgets();
g.flip();
}
}
function plotGraph(info, style) { "ram"
function plotGraph(info, style) { "ram"
E.showMenu(); // remove menu
E.showMessage(/*LANG*/"Calculating...",/*LANG*/"Track "+info.fn);
var filename = info.filename;
@ -433,9 +436,6 @@ function viewTrack(filename, info) {
viewTrack(info.filename, info);
}, isBTN3?BTN3:BTN1);
g.flip();
}
return E.showMenu(menu);
}

View File

@ -2,7 +2,7 @@
"id": "recorder",
"name": "Recorder",
"shortName": "Recorder",
"version": "0.37",
"version": "0.38",
"description": "Record GPS position, heart rate and more in the background, then download to your PC.",
"icon": "app.png",
"tags": "tool,outdoors,gps,widget,clkinfo",