Author Topic: How to program Oak when using with local server?  (Read 8993 times)

malaire

  • Newbie
  • *
  • Posts: 28
How to program Oak when using with local server?
« on: December 27, 2016, 05:30:40 am »
How should I program my Oak when using it with local server?

I read about programming via serial, but that seems to overwrite system firmware. Wouldn't that mean that Oak wouldn't be able to connect to local server anymore, or have I understood this wrong?

PeterF

  • Hero Member
  • *****
  • Posts: 883
Re: How to program Oak when using with local server?
« Reply #1 on: December 27, 2016, 05:11:25 pm »
If the system firmware was overwritten it wouldn't make any difference, as the config settings should be stored elsewhere.

It seems we are supposed to use the particle-cli flash and compile commands once the particle-cli has been configured for local server mode. However, I somehow don't see the compile option working, as the doc references the photon and core only. However, it is fairly painless to compile with the Arduino IDE and get the binary... (Sketch -> Export compiled Binary will compile the sketch and copy the binary to the sketch folder). This works well enough when on the particle cloud or the local server, and the particle-cli allows switching as easily as particle config particle or particle config local.

Have you had any luck with getting the Oak to link to the local server yet?

malaire

  • Newbie
  • *
  • Posts: 28
Re: How to program Oak when using with local server?
« Reply #2 on: December 28, 2016, 03:08:40 am »
Have you had any luck with getting the Oak to link to the local server yet?
I was having some problems, but since that might've been caused by me using 5V USB-Serial, I'll start again with new Oak and 3.3V USB-Serial which I've now got.

It seems we are supposed to use the particle-cli flash and compile commands once the particle-cli has been configured for local server mode. However, I somehow don't see the compile option working, as the doc references the photon and core only. However, it is fairly painless to compile with the Arduino IDE and get the binary... (Sketch -> Export compiled Binary will compile the sketch and copy the binary to the sketch folder). This works well enough when on the particle cloud or the local server, and the particle-cli allows switching as easily as particle config particle or particle config local.

I think I first try programming my old Oak which is connected to Particle, using Arduino IDE -> Export and then particle-cli, to confirm that I can do this on Raspberry Pi.

Then I will try same with local server and new Oak (which is still at fresh state, hasn't even been powered on ever).

PeterF

  • Hero Member
  • *****
  • Posts: 883
Re: How to program Oak when using with local server?
« Reply #3 on: December 28, 2016, 04:32:59 pm »
Hm... I must have changed that last sentence mid thought...  I meant particle-cli seems to works well enough when on the cloud, and  particle-cli switches between the local and particle cloud configs easily enough... I haven't gotten the local cloud working yet :-( ... I've decided to start again but with a windows box as the server, just in case there is something hinky about the rPi setup. I just had to install spark-server from scratch as the windows zip wasn't happy with my Win10 x64 box - something about invalid binaries.

Sounds like a plan... Hopefully you'll get *something* happening this time! :-)

Later in the day:

Well, I didn't bother with the windows box just yet... I kept working on the rPi, and am going to admit defeat for the day. After having an argument with two Oaks which didn't want me to configure them anymore, I serial flashed OakSystem onto them with DEBUG_SERIAL enabled in the core, disabled their ability to connect to particle, and was able to knock some sense into them. Looks like they really didn't like being able to connect to WiFi but not handshake with particle.

I found the following lines were what I needed to reset at least one of them back to particle when using the serial terminal (115200 baud with LF line endings, although CRLF should work also). The first block sets the server and address type (domain or IP), and the second sets the public key. Command format is command, length of data, and data.

Code: [Select]
set
60
{"server-address":"device.spark.io","server-address-type":1}

set
828
{"server-public-key":"30820122300d06092a864886f70d01010105000382010f003082010a0282010100beccbe43db8eea1527a6bb526de1512ba0abcca1647748ad7c66fc807ff699a525f2f2dae043cf3a26a49ba187030e9a8d239abcea99ea68d35a14b1260fbdaa6d6f0cacc4772cd1c5c8b1d17b68e025737b52896820bd06c6f0e60030c0e0cff61b3a45e9c45b551706a3d34ac6d5b8d21702b5277d8de4d47dd3edc01d8a7c251e214a51ae5706dd60bca13490aacc099e3b3a414c3c9df3fdfdb727c159819854604a627aa49abfdf921b3efca7e4a4b33a9a5f57938eeb196495224a2cd560f5f9d003508369c06b53f0f0daf813821fccbb5fe2c1df3ae97f5de27db950803c5833ef8cf3803f1101d268865f3c5ee6c18e322b28cbb5cc1ba8505ea70d0203010001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff010f6465766963652e737061726b2e696f00"}

Now that I can easily switch between the local cloud and particle regardless of what state the Oaks are in, I can go fiddling further to see what I can break. Next thing to work out is why when the Oak should be able to see the local server as its on the same network it says it's unable to receive key when handshaking.

Code: [Select]
WIFI CONNECT
WIFI CONNECTED
PARTICLE CONNECT
AUTO CONNECT
START HANDSHAKE
SHAKE
4
BLRECV
40
SHAKE1
4
SHAKE2
BLSEND
256
0
SHAKE3
SHAKE4
BLRECV
Handshake: Unable to receive key
« Last Edit: December 28, 2016, 09:39:19 pm by PeterF »

malaire

  • Newbie
  • *
  • Posts: 28
Re: How to program Oak when using with local server?
« Reply #4 on: December 29, 2016, 11:35:45 pm »
I just fixed a bug in my oak-get-device-key.pl script, device key needs to be converted from DER to PEM format before saving it to core_keys directory.

I now get 'Core online!' from local server, so Oak seems to connect properly. (I havn't tried to program it yet.)

EDIT: About compiling for Oak on Raspberry Pi: installing Oak support to Arduino IDE does not work because some required binaries are not available for ARM (I suspected this might be the case). Initially it's probably easiest to compile on other computer and send exported binary to Raspberry Pi for flashing, but later I could try creating required binaries from source.
« Last Edit: December 30, 2016, 12:24:31 am by malaire »

PeterF

  • Hero Member
  • *****
  • Posts: 883
Re: How to program Oak when using with local server?
« Reply #5 on: December 30, 2016, 02:09:04 am »
Nice! You've gotten further than I have then... I have yet to see any response from the local server that the Oak is connecting. I can interigate the local server with particle-cli, and but because the Oak isn't connecting properly don't get any further.

I wonder if the

Code: [Select]
"-----BEGIN PUBLIC KEY-----"
"-----END PUBLIC KEY-----"

bits are all that are missing... would be nice if that is the case! :) Will investigate again tomorrow.

btw, since you can run particle cli on another machine... you would be able to get the binary on your desktop/laptop, and then run particle-cli to send the compiled binary to the oak via the rPi local server. But it would be nice to see the Oak on the rPi also... :)

malaire

  • Newbie
  • *
  • Posts: 28
Re: How to program Oak when using with local server?
« Reply #6 on: December 30, 2016, 02:13:25 am »
ok, I now did a flashing test with Oak using particle-cli on Raspberry Pi - both with Particle-cloud connected Oak and with local-server-connected Oak.

First I created few binaries on my Debian computer and moved them to Raspberry Pi. To confirm that these works, I used particle-cli to flash an Oak which is connected to Particle cloud:

Code: [Select]
particle config particle
particle cloud login
particle list
particle flash <DEVICE_ID> blink1000.bin

Then I tried same with local server and different Oak which has only ever been connected to this local server:
Code: [Select]
particle config local_oak
particle list
particle flash <DEVICE> blink1000.bin

Flashing Particle-connected Oak works (which confirms that binary is OK), but flashing local-server connected Oak does not work.

Below is server log for: start server, power on Oak, issue 'particle flash' command

Code: [Select]
Loading user <EMAIL>
connect.multipart() will be removed in connect 3.0
visit https://github.com/senchalabs/connect/wiki/Connect-3.0 for alternatives
connect.limit() will be removed in connect 3.0
Starting server, listening on 8080
static class init!
found <DEVICE_ID>
Loading server key from default_key.pem
set server key
server public key is:  -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqVSreWHbxnixtcZBEV2S
J4sNXGp/iMIWV6+l5vv9OAhnNLdQGK7JY6HyztB+sh9DxxoRbNRf7/zzXERMUJ/R
uX1+uNSk1p/j9kSfFbtCpLm2QwqfPgXdImAnq1HdIMxrkT/zxiJjUW6+dIm/mPlU
PUtiOntVtqDKgE31Z1vKA6FJ2zN5x1GykRU7UP1/B6DRZc9sMN6HIsmnNt3uC7Y+
YaypOqQAurFB8z1Tq0PvQDWhrCVOeG41EmXWnLQtFi8tKYbrjZdMqe4woZ5bvahn
aVVhLTh9Ata37V2e+ANt0UqB4Wg5IXx3zbvqSPNnK19wQUcOMU8HdfowdXBSjgNo
XQIDAQAB
-----END PUBLIC KEY-----

Your server IP address is: 192.168.11.28
server started { host: 'localhost', port: 5683 }
Connection from: ::ffff:192.168.11.214, connId: 1
on ready { coreID: '<DEVICE_ID>',
  ip: '::ffff:192.168.11.214',
  product_id: 82,
  firmware_version: 0,
  cache_key: '_0' }
Core online!
GetAttr { coreID: '<DEVICE_ID>',
  userID: '<USER_ID>' }
::ffff:192.168.11.28 - - [Fri, 30 Dec 2016 09:26:37 GMT] "GET /v1/devices/<DEVICE_ID>?access_token=<TOKEN> HTTP/1.1" 200 113 "-" "-"
set_core_attributes { coreID: '<DEVICE_ID>',
  userID: '<USER_ID>' }
FlashCore { coreID: '<DEVICE_ID>',
  userID: '<USER_ID>' }
flash core started! - sending api event { coreID: '<DEVICE_ID>' }
::ffff:192.168.11.28 - - [Fri, 30 Dec 2016 09:26:38 GMT] "PUT /v1/devices/<DEVICE_ID>?access_token=<TOKEN> HTTP/1.1" 200 68 "-" "-"
on response, no chunk, transfer done!
Flasher - failed sending updateDone message
releasing flash ownership  { coreID: '<DEVICE_ID>' }
flash core finished! - sending api event { coreID: '<DEVICE_ID>' }
onSocketData called, but no data sent.
routeMessage got a NULL coap message  { coreID: '<DEVICE_ID>' }
1: Core disconnected: socket close false { coreID: '<DEVICE_ID>',
  cache_key: '_0',
  duration: 76.541 }
Session ended for _0
Connection from: ::ffff:192.168.11.214, connId: 2
on ready { coreID: '<DEVICE_ID>',
  ip: '::ffff:192.168.11.214',
  product_id: 82,
  firmware_version: 0,
  cache_key: '_1' }
Core online!
Flasher failed failed waiting on CompleteTransfer
releasing flash ownership  { coreID: '<DEVICE_ID>' }
Flasher - already succeeded, not an error: failed waiting on CompleteTransfer
« Last Edit: December 30, 2016, 04:38:50 am by malaire »

malaire

  • Newbie
  • *
  • Posts: 28
Re: How to program Oak when using with local server?
« Reply #7 on: December 30, 2016, 02:21:45 am »
I wonder if the
Code: [Select]
"-----BEGIN PUBLIC KEY-----"
"-----END PUBLIC KEY-----"
bits are all that are missing... would be nice if that is the case! :) Will investigate again tomorrow.
Also the part in between those lines is DER-format but in base64-encoding:
https://github.com/malaire/oak-with-rpi-server/blob/1310a4e7b1d4026366bc6a89d9dbb95ea16074f8/oak-get-device-key.pl#L83

malaire

  • Newbie
  • *
  • Posts: 28
Re: How to program Oak when using with local server?
« Reply #8 on: December 31, 2016, 05:23:20 am »
I think I have to give up on this, my skills aren't good enough to make this work.

I tried same steps I was using, with yet another Oak, but this time it didn't connect to server:

Code: [Select]
...
Your server IP address is: 192.168.11.28
server started { host: 'localhost', port: 5683 }
Connection from: ::ffff:192.168.11.226, connId: 1
onSocketData called, but no data sent.
1: Core disconnected: socket close false { coreID: 'unknown', cache_key: '_0' }
Session ended for _0
Connection from: ::ffff:192.168.11.226, connId: 2
onSocketData called, but no data sent.
1: Core disconnected: socket close false { coreID: 'unknown', cache_key: '_1' }
Session ended for _1
Connection from: ::ffff:192.168.11.226, connId: 3
Handshake failed:  read_coreid timed out { ip: '::ffff:192.168.11.226', cache_key: '_0', coreID: null }
Handshake failed:  read_coreid timed out { ip: '::ffff:192.168.11.226', cache_key: '_1', coreID: null }
1: Core disconnected: read_coreid timed out { coreID: 'unknown', cache_key: '_2' }
Session ended for _2
Handshake failed:  read_coreid timed out { ip: '::ffff:192.168.11.226', cache_key: '_2', coreID: null }

Also neither of the Oaks I've been using with local server shows AP when in config mode, which makes it impossible to change some of the settings, e.g. server key or wifi settings.

PeterF

  • Hero Member
  • *****
  • Posts: 883
Re: How to program Oak when using with local server?
« Reply #9 on: December 31, 2016, 06:41:43 pm »
Sounds like you hit a similar problem to what I did when I was trying last... the Oak was failing to handshake with the server, so it when into some sort of spastic mode, hence the need to flash some serial firmware on without any particle support, so I could reconfigure the 'lil sucker. I tried again yesterday afternoon, and seem to have hit a different snag... I was finally able to connect to the Oaks AP with the RPi, so I was able to use your latest get-device-id and set-server scripts, which seemed to work fine. But my Oak still didn't co-operate. So I put it back into serial debug mode sans-particle, and it looks like it didn't take the set-server parameters... and when I try to configure them via serial it says it succeeded (r:0), but checking the settings afterwards on the info page reveals that they haven't changed... so for some reason even after a complete restore neither of these Oaks are letting me change the server settings, which is absoutely nuts as I am using the same settings I was able to use two days earlier!!!!

digistump

  • Administrator
  • Hero Member
  • *****
  • Posts: 1465
Re: How to program Oak when using with local server?
« Reply #10 on: January 15, 2017, 07:44:36 pm »
Peter and Markus - I apologize for my silence on this the last month and a half - we've had 45 days nearly straight of snow and ice storms, with a small farm to take care of and deliveries to keep moving it has been busy but this has remained on my list and I've tried to get it to work reliably when I've had a chance - unfortunately my results have been about as mixed as your guys - here is what I've discovered:

I had tested connecting to the local server and sending data back and forth - I guess I had not tested flashing (compile can't work but as you guys figured out you can grab the bin file, and if/when it did work I could make a Arduino board profile that would do this automatically)

Flashing: after digging deep into this - it looks like the local sever from particle uses a much earlier implementation of the flashing protocol - ah! - I've been told many time that Particle updating the local server to the current API is a priority "right after X" - while that was believable when the decision to go to Particle was made, since they are not even taking most pull requests on it now that seems less likely to happen soon

Oaks Connecting: When I tested my Oaks worked pretty quickly, I did this on windows and didn't have any special characters in anything (SSID, server, etc) of course I have an advantage (disadvantage for testing) of being too familiar with Oaks and working on the machine they were developed on with all the tools installed. Further testing more recently I saw reliability issues with getting them to connect to the local server - which seem to be related to keys - but did not see the issues with getting the server settings to change. I think some of these issues are related to the local server retry protocol being either broken or seemingly less robust.

The number of people who have shown any interest in using the local server are very low (probably 5+ out of about 5000) but among those are some of the most dedicated Oak users - you two obviously fall in that lot, you've done alot of work trying to get this to work and I don't want to let you down! At this point fixing the local particle server seems very time consuming, complex, and not entirely likely to get accepted into their branch (thus requiring ongoing maintenance) - so building an alternative local firmware that uses a much more friendly local data cloud (phant, clone of dweet, etc) seems worth looking at - combined with some work I did recently for some contract work, for doing OTA updates without Particle I think I could in a matter of a day make something that worked better and more completely then the Particle local server does - so I plan to pursue that while still hoping Particle will update their local server. If this sounds good, I'll do it this week.


A few questions for anyone following this/needing a local server:

What is your use case? What are the devices sending/receiving?

How important is being able to push/trigger a function on the device? Vs. the device sending data to the master server?

How important is it the data is encrypted given that it remains local and is already (presumably) on an encrypted wifi network?

Which applies more to your use case - being able to push the same sketch to all nodes at once? or being able to push different sketches to different nodes (by each one's id)?

Solice

  • Newbie
  • *
  • Posts: 23
Re: How to program Oak when using with local server?
« Reply #11 on: January 15, 2017, 08:17:34 pm »
Some of these questions have complex answers, but I'll try to add what I can without invoking the elemental plane of text.

My general use case with anything that I currently plan to build will not be a commercial product, so data interception is a concern, but a much lower one than some others may have.  This will generally involve sending sensor data to a specific address, using an HTTP POST request.  Any remote sensor nodes that I develop may periodically send an HTTP GET request to update sensor settings.  That being said, I'm not all that concerned about a boxed cloud solution unless it was ridiculously easy to use.  I'm a database programmer for a college, so I might as well do something fun with those skills anyway.  Right now, I have a project in the works using modules similar to the Oak that issues HTTP requests to a Raspberry Pi running a Python and Flask script to respond to the HTTP requests.  The Oak's job in this scenario would be to collect and send data.  That's an important distinction in the overall design of my projects; the Oaks would never have to actively listen for and poll for incoming connections to sidestep some issues that can occur when the guts of the code is hogging the MCU and not able to properly deal with the radio.

When it comes to OTA updates, I think it's a great feature, but only if it does not rely on security through obscurity.  I don't mind having to walk to all nodes to update them physically if it means that someone with a will and a common access method to all Oaks won't be able to nuke or hijack them.

If anything I've said evokes more questions, feel free to.

Short answers:

What is your use case? What are the devices sending/receiving?
[ sensor data, periodically; by the minute, not millisecond ]

How important is being able to push/trigger a function on the device? Vs. the device sending data to the master server?
[ for my applications, not very ]

How important is it the data is encrypted given that it remains local and is already (presumably) on an encrypted wifi network?
[ application layer (ie. HTTPS) would be fantastic, but not a requirement for me ]

Which applies more to your use case - being able to push the same sketch to all nodes at once? or being able to push different sketches to different nodes (by each one's id)?
[ if I were to do OTA updates of sketches, I would want per-node control ]

PeterF

  • Hero Member
  • *****
  • Posts: 883
Re: How to program Oak when using with local server?
« Reply #12 on: January 15, 2017, 10:36:51 pm »
I'll (try to) avoid the wall of text by keeping it short and sweet (if you can believe that!).

Basically, my use case at the moment is sensor data (ints, floats). I was hoping for the local server so that if I wanted to take my whole Oak fleet off the 'net I could - but if the local server is going to continue to be a little (starts with S, ends with T, and has an HI in the middle ;D )... then I would probably opt for the path of least resistance and go the ESP8266 OTA route of programming (now that I have reliable ESP8266s with memory big enough to allow OTA programming), and do something against a local thingspeak or phant server (hm... that looks interesting!)

What is your use case? What are the devices sending/receiving?
[ sensor data, by the minute / 10 minutes, not time sensitive or critical ]

How important is being able to push/trigger a function on the device? Vs. the device sending data to the master server?
[ not important, but in the 'nice to have' category  - especially if another device can trigger / push ]

How important is it the data is encrypted given that it remains local and is already (presumably) on an encrypted wifi network?
[ no need whatsoever... encrypted wifi network ]

Which applies more to your use case - being able to push the same sketch to all nodes at once? or being able to push different sketches to different nodes (by each one's id)?
[ being able to push different sketches to different nodes ]

Stay warm, stay safe and don't stress (although I'm expecting to see a functioning alternative to the local server in two weeks time now do you hear me! :-P)! Sounds like you had plenty of snow for Christmas though! ;)

malaire

  • Newbie
  • *
  • Posts: 28
Re: How to program Oak when using with local server?
« Reply #13 on: January 15, 2017, 11:17:19 pm »
Flashing: after digging deep into this - it looks like the local sever from particle uses a much earlier implementation of the flashing protocol ...
Thank you for these details, it's always nice to know why something doesn't work.

... but did not see the issues with getting the server settings to change.
My problem here is that when, after testing an Oak with local server, I put it to config mode (connect Pin 1 to GND), it does not create an AP anymore so I can't connect to it and change settings. (I do get triple-blink so I know Oak is in config mode.)

What is your use case? What are the devices sending/receiving?
Sending sensor data, frequency being from few times per minute to few times per hour.
For some devices I want to receive data to show to user, e.g. with leds or small displays.

How important is being able to push/trigger a function on the device? Vs. the device sending data to the master server?
Device has to be able to send data to master server and pull data from master server.
Server pushing data to device isn't essential, but would be useful. However I could just pull data every minute or so (usually) and every few seconds (for devices which require realtime updates).

How important is it the data is encrypted given that it remains local and is already (presumably) on an encrypted wifi network?
Not important. WPA2 encryption on WiFi is enough.
For OTA updates a simple checksum would be enough for me, to guard against accidental corruption.

Which applies more to your use case - being able to push the same sketch to all nodes at once? or being able to push different sketches to different nodes (by each one's id)?
Each node would be running different sketch.

digistump

  • Administrator
  • Hero Member
  • *****
  • Posts: 1465
Re: How to program Oak when using with local server?
« Reply #14 on: January 18, 2017, 09:50:33 pm »
Thank you all for the feedback - I'm working on a new local server and firmware to go with it, it is about 75% done and based heavily on some contract work I've done over the last 6 months - I hope to finish it late this week or early next.

Here is the work in progress readme for it that outlines the functionality - it is written in Javascript and runs on Node.JS with no binary dependencies so it will work on any platform node works on without hassle. It can use a built in sqlite database or a mysql server for data storage which makes it possible to integrate with the database directly as well as the API - more to come!



**SUBSCRIBE**

POST to /subscribe/[key]
POST body is URL for Webhook or ID,CallbackSlot for Device

or stumpSubscribe(String key, StumpCallbackFunction) returns true/false
   callback function: void callback(String data)

**UNSUBSCRIBE**

POST to /unsubscribe/[key]
POST body is URL for Webhook to unsubscribe

or stumpUnsubscribe() returns true/false - unsubscribes from ALL events the device is subscribed to


**PUBLISH**

POST to /[key]
POST body is data

OPTIONAL:

OPTIONAL: add ?from=NAME to set the name of who/what published that data (automatically set for devices). "from" cannot contain any commas, newlines, or similar

or stumpPublish(String key, String data) returns true/false

**DEVICE SPECIFIC COMMANDS**

To publish to a specific device do a publish to /devices/DEVICE_ID - this data will be sent to the device's callback set by stumpDeviceMessage() in the device sketch and not available anywhere else

To reboot a device publish any data to /devices/DEVICE_ID/reboot

To flash a device programatically POST the .bin file you'd like to flash to /devices/DEVICE_ID/flash - returns 200 regardless of whether it flashes.
The device will check to see if it is different then current firmware first so calling periodically will not result in continously flashing the device.
The file will be set to the new firmware for the device (until overridden from a command or the Arduino IDE), so when the device checks in after power on/reboot it will update if it is not yet current.


**DEVICE GROUPS FOR FLASHING**

To add a device to a group (or create a new group) POST the DEVICE_ID to /groups/GROUP_NAME

To remove a device from a group GET to /groups/GROUP_NAME/DEVICE_ID

To reboot a group publish any data to /groups/GROUP_NAME/reboot

To flash a group programatically POST the .bin file you'd like to flash to /groups/GROUP_NAME/flash - returns 200 regardless of whether it flashes.
The device will check to see if it is different then current firmware first so calling periodically will not result in continously flashing the device.
The file will be set to the new firmware for devices in that group (until overridden from a command or the Arduino IDE), so when a device checks in after power on/reboot it will update if it is not yet current.
If the flash device is used after a flash group or vice versa, the most recently uploaded file will be sent to that device.


**GET CURRENT DATA**

GET to /[key]

or stumpGet(String key) returns data as String

**GET RANGE OF DATA**

GET to /[key]?start=DATETIME&end=DATETIME

where DATETIME is any string the works with PHP's strtotime() (http://php.net/manual/en/function.strtotime.php) - NOTE: strtotime() is not actually used, but acceptable syntax should be identical

omitting end (or setting it to "all") will return all results from the defined start through the current time

omitting start (or setting it to "all") will return all results until the defined end

GET to /[key]?limit=X

where X is the number of results you want returned will return X newest results (or less if X are not available) - can combine with start or end

omitting all three options will return only the most recent result - use ?start=all and omit end or set it to "all" to get all results

**GET DATA ONLY FROM ONE DEVICE/CLIENT**

GET to /[key]?from=NAME

**KEY RULES**

Must be valid URL characters (rfc3986) or URL encoded, may not contain an asterisk (see wildcards).

Cannot start with "subscribe/", "device/", or "stream/"

Wildcards: Use a wildcard/asterisk "*" at the end of a key to get all keys that start with that key (inclusive) - only a single wildcard may be used and only at the end of a key

GET to /* will get the most recent data from any key. Use /* with other options to get a range of all data.

**GET FORMATS**

You can optionally append the following to a get request URL for various formats:

?type=json [DEFAULT]
   Returns a json object (or array of objects for multiple results) that includes key, data, from, and timestamp.

?type=csv
   Returns a csv file with one line per result in the following format - key, data, from, and timestamp. Double quotes will enclose the data.

?type=csvh
   Returns a csv file with one line per result in the following format - key, data, from, and timestamp. Double quotes will enclose the data. The first line will be a header with the field names.

?type=raw
   Returns a plaintext file with only the data on one line per result

**WEBSOCK**

Open a websocket connection to /[key] to open a websocket connection for all new events sent to that key.

NOTE: when it first opens there may be no data shown, it will not show until a new data item is published to that key

Wildcard can be used on this as well. GET to /* will get new data for all keys.

This will always use JSON format and will send one event at a time.

SPECIAL CASE: Open a websocket connection to /debug to get all new events and debuggin info on connections and other actions