-
-
Hi,
Well, from the error log it looks like this line of the script is failing:sudo setcap cap_net_raw+eip $(eval readlink -f `which node`)
readlink
isn't getting a parameter, and so is returning nothing; and sosetcap
is missing that parameter too. The most likely answer to this is thatwhich node
is failing, ie.node
can't be found.Since you say
start.sh
run manually is working, I'd say that it's not thatnode
(andnpm
, since you're having trouble with that too) isn't installed at all, but that it's not in the path for the user under whichnode-red
is being run. That'd imply a slightly non-standard installation of Node, at least as far as the assumptions of this script are concerned (...or perhaps we've been using a non-standard Node!)Did you start with a Raspbian that has Node and Node-RED preinstalled? If not, I'd start by redoing the installation of Node. If so, maybe there's a problem with our script and that
start.sh
should be a little more aggressive about finding it, rather than just assuming it's in$PATH
.Please can you try:
which node
whereis node
nave ls
(might fail) -
Another day, another rewrite :)
I've actually got it working now, although I'm still not sure what I changed. I stripped out pretty much everything, rewrote, and then rigged it so
on('disconnect')
executesNRF.sleep()
... the idea being that when the Puck disconnects (for whatever reason), it won't reconnect until manually woken by a keypress.I don't mess with advertising or services beyond the initial setup, which unfortunately loses the battery monitor; however, that doesn't seem to make much difference anyway: the device is either connected (no advertising?) or disconnected and sleeping (no advertising)
I'm also not sure what the drain on this is. Next I'll have to rig it up to test power consumption while sleeping, as that's the ultimate aim. I also have to solve the auto-switch-off that triggered this whole matter in the first place; I'm hoping it's just a case of
setTimeout(...NRF.disconnect()..., 1000*60*10) ... clearTimeout()
.For the benefit of anyone else attempting this - https://gist.github.com/tomgidden/875b5a5522deeabd9d1ef389607e434a :
var hid = require("ble_hid_keyboard"); var is_connected = false; var ad_values = {}; var ad_options = { name: "Page-Turn-o-Matic 4000" }; var sleep_timeout; // Object to handle multiple-clicking and long-clicking on // a button, using EventEmitter. function Btn(btn) { var o = this; o.es = [0,'click','double','triple','quadruple']; o.br = function (e) { if ( 2.0 < e.time - e.lastTime) { if (o.h) clearTimeout(o.h); o.i = o.h = o.l = undefined; o.emit('long', 0); } else { // If there's no previous click or it's more than // a second ago, it's a new chain of clicks. if (!o.i || !o.l || 1.0 < e.time - o.l) o.i = 1; else o.i ++; o.l = e.time; if (o.h) clearTimeout(o.h); o.h = setTimeout(function () { o.h = undefined; if (o.es[o.i]) o.emit(o.es[o.i], o.i); o.i = 0; }, 400); } }; o.w = setWatch(o.br, btn, { repeat:true, edge:'falling', debounce : 50 }); return o; } var btn; function blinken (colour, count) { digitalWrite([LED1,LED2,LED3], colour); setTimeout(function(){ digitalWrite([LED1,LED2,LED3], 0); if (count > 1) { setTimeout(function () { blinken(colour, --count); }, 50); } }, 25); } function set_sleep_timeout() { if (sleep_timeout) clearTimeout(sleep_timeout); sleep_timeout = setTimeout(function () { clear_sleep_timeout(); NRF.disconnect(); }, 1000*60*5); } function clear_sleep_timeout() { if (sleep_timeout) { clearTimeout(sleep_timeout); sleep_timeout = undefined; } } // Connection tracking function on_connect () { blinken(0b011); is_connected = true; } function on_disconnect() { clear_sleep_timeout(); blinken(0b101); is_connected = false; NRF.sleep(); // Prevent reconnection until manually woken } // Button click events function on_click (c) { set_sleep_timeout(); if (is_connected) { // Single flash - move right blinken(0b010, 1); hid.tap(hid.KEY.RIGHT, 0); } else { NRF.wake(); blinken(0b001); } } function on_double (c) { set_sleep_timeout(); if (is_connected) { // Double flash - move left blinken(0b010, 2); hid.tap(hid.KEY.LEFT, 0); } else { NRF.wake(); blinken(0b001); } } function on_triple (c) { NRF.disconnect(); // on('disconnect') causes NRF.sleep } function on_quadruple (c) { blinken(0b110); NRF.wake(); } // Initialisation function init () { NRF.on('connect', on_connect); NRF.on('disconnect', on_disconnect); NRF.setAdvertising({}, ad_options); NRF.setServices(undefined, { hid : hid.report }); btn = new Btn(BTN); btn.on('click', on_click); btn.on('double', on_double); btn.on('triple', on_triple); btn.on('quadruple', on_quadruple); console.log("Note: to activate, either disconnect manually, or NRF.disconnect();"); } E.on('init', init);
(updated with auto-sleep)
-
The delay during
init
is really so it can do a disconnect -- and hence do theset*
calls without queueing -- without interfering with the upload loop. I've found that ifonInit
immediately disconnects, it can confuse the IDE.I've run out of batteries for the pucks right now -- I've been away from home this weekend -- but I think the code works fine until
sleep
andwake
get involved. After that, it's all a bit unpredictable. Now I've got a barebones implementation, I'll try to add them back in. -
Hmm. Something's getting stuck, I think.
With this stripped-down code on 1v92.91; after a power cycle and an
E.setBootCode("");
, an upload and a refresh, I get Error 13313 when clicking. However, if IRemove
(ie. unpair and forget) the Puck with Opt-click on the menu bar, it works okay.var hid = require("ble_hid_keyboard"); var is_connected = false; var ad_values = {}; var ad_options = { name: "Page-Turn-o-Matic 4000" }; function on_connect () { digitalPulse(LED3, true, 100); is_connected = true; } function on_disconnect() { digitalPulse(LED1, true, 100); is_connected = false; } function btn_released() { if (is_connected) { digitalPulse(LED2, true, 100); hid.tap(hid.KEY.RIGHT, 0); } else digitalPulse(LED1, true, 500); } function init () { NRF.on('connect', on_connect); NRF.on('disconnect', on_disconnect); clearWatch(); setTimeout(function () { setWatch(btn_released, BTN, { repeat:true, edge:'falling', debounce : 50 }); NRF.disconnect(); // ad_values[0x180F] = Math.round(Puck.getBatteryPercentage()); NRF.setAdvertising(ad_values, ad_options); NRF.setServices(undefined, { hid : hid.report }); }, 3000); } E.on('init', init);
I'll start putting stuff back in, bit-by-bit, and unpair if/when it goes bad. It's times like these I really wish Puck had a USB port.
-
I haven't tried having a delay per se., but when it's connected to the IDE and producing 13313 errors, it'll do it whenever the button is pressed, repeatedly for as long as you like.
I have been running
setServices
andsetAdvertising
whenever it comes out of sleep withNRF.wake()
too... I wasn't sure if doingNRF.sleep()
wiped the existing records. Regardless, I was trying to dosetAdvertising()
to update the battery level, so it would need to be called repeatedly.To be honest, the lack of an
isConnected()
and anisSleeping()
method is a bit inconvenient. Getting the status of the softdevice would be useful, rather than trying to track it manually. -
The
Error 13313
s seem to come whenhid.tap()
calls are made on a HID connection while also doingNRF.disconnect()
,NRF.sleep()
,NRF.wake()
in various combinations. I'm not entirely sure yet. I think it might be a case of the service characteristics getting lost after anNRF.wake()
, but redoing them fails too. I'm seeing these 13313 errors in the Espruino IDE when connected with Web Bluetooth, so there is a connection open with the computer, albeit UART.BLE_ERROR_GATTS_SYS_ATTR_MISSING
composes to13313
. Pertinent? https://devzone.nordicsemi.com/question/6085/strange-error-code-13313-0x3401-returned-by-sd_ble_gatts_hvx/?answer=6106#post-id-6106The context: the script sets timeouts to make it execute
NRF.disconnect(); ... NRF.sleep()
after a set time (5 mins) of inactivity; each button press willclearTimeout()
and start a new 5 minute timeout. Then, when the button is pressed, anNRF.wake()
call is made if necessary, beforehid.tap()
is called subsequently on release.When this behaviour works (it has sporadically worked in random hack versions along the way) it works really well - the Puck disconnects and shuts down when idle, and then wakes up and posts a keypress when it's activated with a click (forward) or a double-click (back)
And, if the on-screen keyboard is wanted, you can prematurely disconnect and sleep the Puck with a triple-click. That also acts as a manual "Off" when you remember to do so rather than idling it for five minutes.
A long click does a disconnect without a sleep, allowing Web Bluetooth to see the Puck for long enough to connect to it for maintenance.
Anyway, I wouldn't analyse that too much: part of the problem of getting you a neat little test case is the unpredictability, and the limitation of debugging while also having connects and disconnects, sleep and wake happen at the same time... I'm mainly working on cryptic LED flashes. I am still trying to isolate it though. My weekend's packed, unfortunately.
-
Thanks… that does seem better as far as the
ERROR 0x8
fatal crashes are concerned. I'm still having trouble with a lot ofBLE error 13313
s, though... looks like my services are getting munged, or something like that.I'm not really too sure about the order of execution here, and what's necessary in what order; such as whether
NRF.setAdvertising()
needs to be called after anNRF.wake()
, whetherNRF.setServices()
needs to be called after aNRF.setAdvertising()
. A simple test rig seems to work fine, but as soon as I start introducing a) HID and b) NRF.sleep/wake, it all starts going horribly wrong.I expect this would be easier if I wasn't trying to do HID and UART through Web Bluetooth (which is hinky at the best of times) but finding a USB-to-Serial or rigging a Pico to do the same job and then trying to connect to the Puck non-destructively is a big PITA. I'm also suspicious of connecting to Espruinos via serial because whenever I've tried the different redirection of the console seems to change behaviour subtly.
Anyhoo. I'll soldier on. Thanks
-
I was going to say I've managed to isolate it down to a few lines of code, but ended up with this situation:
=undefined _____ _ | __|___ ___ ___ _ _|_|___ ___ | __|_ -| . | _| | | | | . | |_____|___| _|_| |___|_|_|_|___| |_| http://espruino.com 1v92 Copyright 2016 G.Williams >dump() pinMode(D29, "input_pulldown", true); =undefined >NRF.setAdvertising({},{name:"Test"}); NRF ERROR 0x8 at ?:0 REBOOTING. Disconnected
Hmm. I think there's something rather wrong. I've DFU'ed it back to 1v92, and tried various resets and flash resets. This is since I started doing
NRF.setLowPowerConnection(true)
, although I've since doneNRF.setLowPowerConnection(false)
a few million times.UPDATE (#3): I've managed to get it (and the other Puck I soft-bricked) back using the five-green-flashes method,
E.setBootCode()
, although that didn't seem to help originally.This is all on 1v92 stock on one puck and 1v92.3045 (a fresh build) on the other.
I think the
NRF ERROR 0x8
is happening when it keeps reconnecting and then advertising changes while the connection is active, or something like that. I'm not sure if that makes sense.I've had big problems with
setLowPowerConnection
, as it messes with the timing, giving me runs of repeated taps.From my limited understanding of BLE, I can see that the idea of getting the client (the iPad) to stop connecting to the Puck is problematic. The only way I can see this working is if I can shut down BLE, or HID advertisement, and then restart it when a button is pressed to wake it up.
setLowPowerConnection
alone might save power, but it won't handle the disconnection I need for keyboard access.I'm still rather unclear on what can and can't be done while connections are open, and so forth. Some commands will queue for the next reset, but things like
NRF.setAdvertising
,NRF.sleep
,NRF.wake
might not have the right guards in there, and I think they may be causing the crashes and reboots.I'm still trying to isolate some code to demonstrate it.
-
Thanks, I'll try that. I do want to get
disconnect
working in some way, as I want it to actively disconnect from the iPad so the iPad doesn't keep thinking it's got an external keyboard; unless I can figure out how to get it to realise that it's not really a keyboard, which I imagine will be nasty -- it's nasty to do in Bluetooth Classic, IIRC.So, do you think keeping track of the HID connection (the
BluetoothRemoteGATTServer
via the Promise, presumably?) and issuing aserver.disconnect()
is the way to go?(EDIT: Oh, hang on... that won't work... these connections are initiated by the iPad; there's no
connect
call going on, and we're the server, so there's noBluetoothRemoteGATTServer
object. Hmm. If acting as a server rather than a client, is there a way to selectively disconnect a connection, or is it just a case ofNRF.disconnect()
and let the UART service and anything else be damned? ) -
After exhausting a CR2032 in about a month, I've been tweaking my page-turner trying to make it more efficient.
I'm wondering about the best approach for saving energy between clicks as well as between sessions. I've got a timeout of ~10 seconds that is reset every time the button is clicked; when the timeout does activate, it performs an
NRF.sleep()
. Then, when the button is clicked, it doesNRF.setServices(...hid...)
andNRF.setAdvertising(...)
.I've tried doing
NRF.wake()
in the button's watch function, as well asNRF.disconnect()
during the sleep routine in an attempt to cut off the connection so the iPad doesn't keep thinking it's attached to a keyboard (and so hide the on-screen keyboard until I switch off Bluetooth)However, I get some weird bugs. With
NRF.disconnect()
reconnecting is unreliable, and sometimes all of the LED light flashes are slowed down, which makes me think there's something else going on.When
NRF.wake()
is included, I get:NRF ERROR 0x8 at ?:0 REBOOTING.
I assume
setDeepSleep()
is not relevant on the Puck, but what would you see to be the right sequence of events for this application?It's to be woken by a button click, and doesn't really require discovery when the device is "cold", so sleeping all of the BLE stuff seems reasonable; I'm not sure if an entire shutdown of the softdevice is in order. Disconnecting any HID connections when the device isn't being used is also desirable for the on-screen keyboard reason given above.
My code's attached, with the
NRF.wake()
andNRF.disconnect()
calls commented out for the time being.Any thoughts?
var hid = require("ble_hid_keyboard"); var long_click = 2000; // 2 seconds var double_click = 250; // 0.25 second // Detect short press ( < 2 seconds) var is_short = false; var short_timeout = false; // Detect fast-click count ( < 0.25 seconds) var clickcount = 0; var clearclick_timeout; // Sleep when not in use. Needs to be long enough that it doesn't // interfere with attempts to connect to it via the IDE. Saying that, // a triple click will postpone the sleep. var sleep_timeout; var sleep_delay = 10000; // 30 seconds var sleep_long_delay = 600000; // 10 minutes function setupSleep(is_long) { if (undefined !== sleep_timeout) clearTimeout(sleep_timeout); // Schedule the sleep function to run in the future. A button click // will reset this timer. sleep_timeout = setTimeout(sleep, is_long ? sleep_long_delay : sleep_delay); } function sleep() { // Flicker the LED to indicate sleep. This is really for debugging digitalWrite([LED1,LED2,LED3], 0x101); setTimeout(function () { // Clear the LED digitalWrite([LED1,LED2,LED3], 0); // Clear the timeout sleep_timeout = undefined; //// Disconnect any running HID sessions -- problematic; doesn't reconnect well. // NRF.disconnect(); // And shut down the chip NRF.sleep(); }, 250); } // Wake is called for two reasons: woken by a button press; and called by // init() for a full reset. function wake() { //// This is VERY problematic: big-time crash in 1v92 // NRF.wake(); // Set up HID (keyboard) services NRF.setServices(undefined, { hid : hid.report }); // Name it NRF.setAdvertising({},{name:"Page-Turn-O-Matic 4000"}); } // Upon reset of the device function init() { // Clear any current button event handlers clearWatch(); // Just in case, we want to make sure this is off. Puck.magOff(); // Set up BLE wake(); // Set up button event handlers for both rising and falling. These will // also take it out of sleepage. setWatch(btnPressed, BTN, { repeat:true, edge:'rising', debounce : 50 }); setWatch(btnReleased, BTN, { repeat:true, edge:'falling', debounce : 50 }); } // The primary action, on a single click function primary() { hid.tap(hid.KEY.RIGHT, 0); } // The secondary action, on a double click function secondary() { hid.tap(hid.KEY.LEFT, 0); } // Triple-click function tertiary() { // Postpone the sleep cycle for a long time (ten minutes) for debug purposes setupSleep(true); } // The reset function, on a long click (>2s) function long() { NRF.disconnect(); init(); } function btnPressed() { // When the button's pressed, we clear the LEDs. Any // LED activity is on _release_ digitalWrite([LED1,LED2,LED3], 0); // Count clicks in chain clickcount ++; // Reset execution of short-click chain if (undefined !== clearclick_timeout) { clearTimeout(clearclick_timeout); clearclick_timeout = undefined; } // Assume it's a short press is_short = true; // Set a timeout for two seconds to recognise a long press short_timeout = setTimeout(function () { // It's been two seconds, so... // Long press detected is_short = false; short_timeout = null; // Full blast RGB digitalWrite([LED1,LED2,LED3], 0x111); // and don't do anything until release... }, long_click); } // Once a chain of repeated rapid clicks is over (ie. // the 0.25 second threshold has passed)... function chainEnded() { var o = clickcount; clickcount = 0; clearclick_timeout = undefined; // Reset the sleep watchdog wake(); setupSleep(); switch (o) { case 1: // Simple click; GREEN digitalWrite([LED1,LED2,LED3], 0b010); primary(); break; case 2: // Double-click; RED digitalWrite([LED1,LED2,LED3], 0b100); secondary(); break; // Triple-click, etc. can be added as additional `case`s. case 3: // Triple-click; YELLOW? digitalWrite([LED1,LED2,LED3], 0b110); tertiary(); break; default: // Too many clicks. Ignore. break; } } function btnReleased() { // `short_timeout` is there to _deny_ a short // click. If it times out, then it means the button // has been held longer than a short click. // // So, for a short click, if the timeout is still going // then clear it: `short` should remain whatever it is, // including `true`. if (short_timeout) { clearTimeout(short_timeout); short_timeout = null; } if (is_short) { // Set a timeout to process short clicks clearclick_timeout = setTimeout(chainEnded, 250); } else { // Long press: reset digitalWrite([LED1,LED2,LED3], 0x001); clearclick_timeout = undefined; long(); } // And clear any LEDs after a reasonable period. setTimeout(function () { digitalWrite([LED1,LED2,LED3], 0); }, double_click); } // Set the initialisation function E.on('init', init);
-
-
I'll give it another go, now that I've got ESP32 functioning for what I want... the micro:bits have the benefit of battery connectors. It's just a real shame they went with the 16kB variant rather than the 32kB.
"Modules as functions" gave me trouble at the time, so I cut-and-pasted a very stripped-down
DS18B20.js
into the top of the source code, and minimised the code manually (still using Esprima et al., though)I think for a restricted platform like micro:bit, almost all modules are going to be a problem as you don't want to compromise the capabilities of those modules for more capable boards, but not maintain two entirely separate trees.
Regardless,
_minimal
confuses with.min
. Maybe,_basic
?_barebones
? -
NPM, installed last night. I made the obvious realisation they were built-in shortly after posting, but locked the thread by accident. This is what happens when I try to code late at night while on heavy medication! :)
It's quite conceivable it'll get confused anyway; I'm using a no-name dev carrier board... a sweet spring-loaded fixture from ebay for programming bare ESP32 modules without soldering.
Thanks!
-
Admittedly, I'm not playing by the rules here -- running CLI
espruino
on a manually-flashed bare ESP32 -- but right now I'm getting:Espruino.Core.Utils.getURL: got HTTP status code 404 for http://www.espruino.com/modules/http.min.js Espruino.Core.Utils.getURL: got HTTP status code 404 for http://www.espruino.com/modules/Wifi.min.js Espruino.Core.Utils.getURL: got HTTP status code 404 for http://www.espruino.com/modules/http.js Module http not found Espruino.Core.Utils.getURL: got HTTP status code 404 for http://www.espruino.com/modules/Wifi.js Module Wifi not found
Shouldn't these files exist? Anyone else getting this? Have I missed something obvious?
Cheers,
Tom -
I've found it very hard to get any useful code running on an Espruino micro:bit, once a module or two is
require
d. The one thing I really worked on was advertising temperatures from some DS18B20 probe on BLE. Absolutely couldn't get it to fit, even with manual stripping and minification of the DS18B20 module.Of course I could just use one of my precious Pucks, but it'd be a waste... they're overkill and I've got three or four spare micro:bits I'm not using. However, I'm just going to use a few bare ESP32 modules instead.
-
Duh. Yes, looks like you've told me to do it before...
http://forum.espruino.com/conversations/302573/#comment13553381
Absolutely no memory of that. :) Moral: don't participate in technical discussions on the internet at two in the morning while heavily medicated.
-
FYI, just for the sake of another data point, I just had the same thing.
I've been using a simple BLE HID controlling script on 1v91.715 for some time. I just flashed it to 1v92, and had the full-on RGB flash and failure to connect. So, DFU back to 1v91, run the
erasePage
bit and then back up to 1v92... sorted. -
It looks to me like
ble_hid_keyboard
andble_hid_controls
might be mutually-exclusive. Is it feasible to send commands in both "mechanisms" without a rewrite of those modules?In the Adafruit Bluefruit LE services AT command API, I seem to remember it's possible to send both
AT+BLEHIDCONTROLKEY
andAT+BLEKEYBOARDCODE
in the same "session" (so to speak). And, a typical Bluetooth keyboard with media keys can obviously do both media controls and keyboard presses simultaneously.I want to be able to send:
ble_hid_keyboard.KEY.RIGHT
on single click;ble_hid_keyboard.KEY.LEFT
on double click;- and a control key (specifically control
0xb8
of the0x0c
Consumer Page, described on pg.77 of the HID Usage Tables PDF) on triple click.
0xb8
is the "Show Keyboard / Eject" key, which should reveal the keyboard on iOS; if you connect even a one-button keyboard in iOS, it assumes you don't want the on-screen keyboard. I don't know of a way to tell iOS that it's a limited "auxiliary" keyboard, so without that, offering the Eject key is a workaround.I assume this is part of the HID report definition -- writing a comprehensive definition encompassing both -- but it's a bit beyond me. I'm wondering if @Gordon might know how to create a unified report definition capable of both, having written the two existing HID modules.
-
(Incidentally, I've just written up the project)
-
Okay, that did the trick: I DFU'ed to 1.91, did the lines above, and then DFU'ed to 1.91.715. It now pairs more successfully.
However, it hasn't been entirely successful. It took about three goes of code tweaking, re-upload, resets, unpair/pair before the iPad would actually do the "page right" function. It's working okay now, even after an
NRF.disconnect()
. I'll keep an eye on it and see if it stops working again.FYI: at least with this firmware,
onInit()
doesn't seem to work. Once reconnected,dump()
yields garbage. -
-
It's actually rigid: Thermomorph / Polymorph, ie. polyester plastic that melts in hot water.
It's so that when I'm relaxing and recovering from back pain, lying down, I can just turn page on iBooks on iPad by sending a "right" keypress. That way I don't have to hold the iPad or reach up to turn page, thus saving my shoulder and upper back muscles from unnecessary tension.
Incidentally, I haven't managed to get the new firmware talking yet. In fact, it's having trouble connecting to the Web IDE. I think my Mac needs a reboot. Still trying.
-
Mmm.. it's like a Puck, but huge and ugly.
They've posted some Node.js code to operate with the default firmware: https://github.com/NordicSemiconductor/Nordic-Thingy52-Nodejs/blob/master/lib/thingy.js
It might be good to try to match the same services and characteristics they're using for their sensor, to get a Puck acting like a Thingy:52 as far as their official App is concerned.