Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of M2XStreamClient by
M2XStreamClient.h@13:0d574742208f, 2014-12-09 (annotated)
- Committer:
- citrusbyte
- Date:
- Tue Dec 09 14:36:16 2014 +0000
- Revision:
- 13:0d574742208f
- Parent:
- 10:4ce9eba38dbe
- Child:
- 14:205076b587fe
Update client library to latest version
Who changed what in which revision?
| User | Revision | Line number | New contents of line |
|---|---|---|---|
| jb8414 | 0:f479e4f4db0e | 1 | #ifndef M2XStreamClient_h |
| jb8414 | 0:f479e4f4db0e | 2 | #define M2XStreamClient_h |
| jb8414 | 0:f479e4f4db0e | 3 | |
| jb8414 | 0:f479e4f4db0e | 4 | #define MIN(a, b) (((a) > (b))?(b):(a)) |
| jb8414 | 0:f479e4f4db0e | 5 | |
| jb8414 | 0:f479e4f4db0e | 6 | #define MBED_PLATFORM |
| jb8414 | 0:f479e4f4db0e | 7 | |
| jb8414 | 0:f479e4f4db0e | 8 | #ifdef ARDUINO_PLATFORM |
| jb8414 | 0:f479e4f4db0e | 9 | #include "Arduino.h" |
| jb8414 | 0:f479e4f4db0e | 10 | |
| citrusbyte | 13:0d574742208f | 11 | #define USER_AGENT "User-Agent: M2X Arduino Client/2.0.0" |
| jb8414 | 0:f479e4f4db0e | 12 | #endif |
| jb8414 | 0:f479e4f4db0e | 13 | |
| jb8414 | 0:f479e4f4db0e | 14 | #ifdef MBED_PLATFORM |
| jb8414 | 0:f479e4f4db0e | 15 | #include "mbed.h" |
| jb8414 | 0:f479e4f4db0e | 16 | |
| citrusbyte | 13:0d574742208f | 17 | #define USER_AGENT "User-Agent: M2X Mbed Client/2.0.0" |
| jb8414 | 0:f479e4f4db0e | 18 | #endif |
| jb8414 | 0:f479e4f4db0e | 19 | |
| jb8414 | 0:f479e4f4db0e | 20 | #include "Client.h" |
| jb8414 | 0:f479e4f4db0e | 21 | #include "NullPrint.h" |
| jb8414 | 0:f479e4f4db0e | 22 | |
| jb8414 | 0:f479e4f4db0e | 23 | #ifdef DEBUG |
| jb8414 | 0:f479e4f4db0e | 24 | #ifdef ARDUINO_PLATFORM |
| jb8414 | 0:f479e4f4db0e | 25 | #define DBG(fmt_, data_) Serial.print(data_) |
| jb8414 | 0:f479e4f4db0e | 26 | #define DBGLN(fmt_, data_) Serial.println(data_) |
| jb8414 | 0:f479e4f4db0e | 27 | #define DBGLNEND Serial.println() |
| jb8414 | 0:f479e4f4db0e | 28 | #endif // ARDUINO_PLATFORM |
| jb8414 | 0:f479e4f4db0e | 29 | |
| jb8414 | 0:f479e4f4db0e | 30 | #ifdef MBED_PLATFORM |
| jb8414 | 0:f479e4f4db0e | 31 | #define DBG(fmt_, data_) printf((fmt_), (data_)) |
| jb8414 | 0:f479e4f4db0e | 32 | #define DBGLN(fmt_, data_) printf((fmt_), (data_)); printf("\n") |
| jb8414 | 0:f479e4f4db0e | 33 | #define DBGLNEND printf("\n") |
| jb8414 | 0:f479e4f4db0e | 34 | #endif // MBED_PLATFORM |
| jb8414 | 0:f479e4f4db0e | 35 | #else |
| jb8414 | 0:f479e4f4db0e | 36 | #define DBG(fmt_, data_) |
| jb8414 | 0:f479e4f4db0e | 37 | #define DBGLN(fmt_, data_) |
| jb8414 | 0:f479e4f4db0e | 38 | #define DBGLNEND |
| jb8414 | 0:f479e4f4db0e | 39 | #endif // DEBUG |
| jb8414 | 0:f479e4f4db0e | 40 | |
| jb8414 | 0:f479e4f4db0e | 41 | #define HEX(t_) ((char) (((t_) > 9) ? ((t_) - 10 + 'A') : ((t_) + '0'))) |
| jb8414 | 0:f479e4f4db0e | 42 | #define MAX_DOUBLE_DIGITS 7 |
| jb8414 | 0:f479e4f4db0e | 43 | |
| jb8414 | 0:f479e4f4db0e | 44 | static const int E_OK = 0; |
| jb8414 | 0:f479e4f4db0e | 45 | static const int E_NOCONNECTION = -1; |
| jb8414 | 0:f479e4f4db0e | 46 | static const int E_DISCONNECTED = -2; |
| jb8414 | 0:f479e4f4db0e | 47 | static const int E_NOTREACHABLE = -3; |
| jb8414 | 0:f479e4f4db0e | 48 | static const int E_INVALID = -4; |
| jb8414 | 0:f479e4f4db0e | 49 | static const int E_JSON_INVALID = -5; |
| jb8414 | 0:f479e4f4db0e | 50 | |
| citrusbyte | 10:4ce9eba38dbe | 51 | /* |
| citrusbyte | 10:4ce9eba38dbe | 52 | * +type+ indicates the value type: 1 for string, 2 for number |
| citrusbyte | 10:4ce9eba38dbe | 53 | * NOTE that the value type here only contains a hint on how |
| citrusbyte | 10:4ce9eba38dbe | 54 | * you can use the value. Even though 2 is returned, the value |
| citrusbyte | 10:4ce9eba38dbe | 55 | * is still stored in (const char *), and atoi/atof is needed to |
| citrusbyte | 10:4ce9eba38dbe | 56 | * get the actual value |
| citrusbyte | 10:4ce9eba38dbe | 57 | */ |
| jb8414 | 0:f479e4f4db0e | 58 | typedef void (*stream_value_read_callback)(const char* at, |
| jb8414 | 0:f479e4f4db0e | 59 | const char* value, |
| jb8414 | 0:f479e4f4db0e | 60 | int index, |
| citrusbyte | 10:4ce9eba38dbe | 61 | void* context, |
| citrusbyte | 10:4ce9eba38dbe | 62 | int type); |
| jb8414 | 0:f479e4f4db0e | 63 | |
| jb8414 | 0:f479e4f4db0e | 64 | typedef void (*location_read_callback)(const char* name, |
| jb8414 | 0:f479e4f4db0e | 65 | double latitude, |
| jb8414 | 0:f479e4f4db0e | 66 | double longitude, |
| jb8414 | 0:f479e4f4db0e | 67 | double elevation, |
| jb8414 | 0:f479e4f4db0e | 68 | const char* timestamp, |
| jb8414 | 0:f479e4f4db0e | 69 | int index, |
| jb8414 | 0:f479e4f4db0e | 70 | void* context); |
| jb8414 | 0:f479e4f4db0e | 71 | |
| jb8414 | 0:f479e4f4db0e | 72 | class M2XStreamClient { |
| jb8414 | 0:f479e4f4db0e | 73 | public: |
| jb8414 | 0:f479e4f4db0e | 74 | static const char* kDefaultM2XHost; |
| jb8414 | 0:f479e4f4db0e | 75 | static const int kDefaultM2XPort = 80; |
| jb8414 | 0:f479e4f4db0e | 76 | |
| jb8414 | 0:f479e4f4db0e | 77 | M2XStreamClient(Client* client, |
| jb8414 | 0:f479e4f4db0e | 78 | const char* key, |
| jb8414 | 0:f479e4f4db0e | 79 | int case_insensitive = 1, |
| jb8414 | 0:f479e4f4db0e | 80 | const char* host = kDefaultM2XHost, |
| jb8414 | 0:f479e4f4db0e | 81 | int port = kDefaultM2XPort); |
| jb8414 | 0:f479e4f4db0e | 82 | |
| citrusbyte | 10:4ce9eba38dbe | 83 | // Push data stream value using PUT request, returns the HTTP status code |
| jb8414 | 0:f479e4f4db0e | 84 | template <class T> |
| citrusbyte | 13:0d574742208f | 85 | int updateStreamValue(const char* deviceId, const char* streamName, T value); |
| jb8414 | 0:f479e4f4db0e | 86 | |
| jb8414 | 0:f479e4f4db0e | 87 | // Post multiple values to M2X all at once. |
| citrusbyte | 13:0d574742208f | 88 | // +deviceId+ - id of the device to post values |
| jb8414 | 0:f479e4f4db0e | 89 | // +streamNum+ - Number of streams to post |
| jb8414 | 0:f479e4f4db0e | 90 | // +names+ - Array of stream names, the length of the array should |
| jb8414 | 0:f479e4f4db0e | 91 | // be exactly +streamNum+ |
| jb8414 | 0:f479e4f4db0e | 92 | // +counts+ - Array of +streamNum+ length, each item in this array |
| jb8414 | 0:f479e4f4db0e | 93 | // containing the number of values we want to post for each stream |
| jb8414 | 0:f479e4f4db0e | 94 | // +ats+ - Timestamps for each value, the length of this array should |
| jb8414 | 0:f479e4f4db0e | 95 | // be the some of all values in +counts+, for the first +counts[0]+ |
| jb8414 | 0:f479e4f4db0e | 96 | // items, the values belong to the first stream, for the following |
| jb8414 | 0:f479e4f4db0e | 97 | // +counts[1]+ number of items, the values belong to the second stream, |
| citrusbyte | 10:4ce9eba38dbe | 98 | // etc. Notice that timestamps are required here: you must provide |
| citrusbyte | 10:4ce9eba38dbe | 99 | // a timestamp for each value posted. |
| jb8414 | 0:f479e4f4db0e | 100 | // +values+ - Values to post. This works the same way as +ats+, the |
| jb8414 | 0:f479e4f4db0e | 101 | // first +counts[0]+ number of items contain values to post to the first |
| jb8414 | 0:f479e4f4db0e | 102 | // stream, the succeeding +counts[1]+ number of items contain values |
| jb8414 | 0:f479e4f4db0e | 103 | // for the second stream, etc. The length of this array should be |
| jb8414 | 0:f479e4f4db0e | 104 | // the sum of all values in +counts+ array. |
| jb8414 | 0:f479e4f4db0e | 105 | template <class T> |
| citrusbyte | 13:0d574742208f | 106 | int postDeviceUpdates(const char* deviceId, int streamNum, |
| citrusbyte | 13:0d574742208f | 107 | const char* names[], const int counts[], |
| citrusbyte | 13:0d574742208f | 108 | const char* ats[], T values[]); |
| jb8414 | 0:f479e4f4db0e | 109 | |
| jb8414 | 0:f479e4f4db0e | 110 | // Fetch values for a particular data stream. Since memory is |
| jb8414 | 0:f479e4f4db0e | 111 | // very limited on an Arduino, we cannot parse and get all the |
| jb8414 | 0:f479e4f4db0e | 112 | // data points in memory. Instead, we use callbacks here: whenever |
| jb8414 | 0:f479e4f4db0e | 113 | // a new data point is parsed, we call the callback using the values, |
| jb8414 | 0:f479e4f4db0e | 114 | // after that, the values will be thrown away to make space for new |
| jb8414 | 0:f479e4f4db0e | 115 | // values. |
| jb8414 | 0:f479e4f4db0e | 116 | // Note that you can also pass in a user-specified context in this |
| jb8414 | 0:f479e4f4db0e | 117 | // function, this context will be passed to the callback function |
| jb8414 | 0:f479e4f4db0e | 118 | // each time we get a data point. |
| jb8414 | 0:f479e4f4db0e | 119 | // For each data point, the callback will be called once. The HTTP |
| jb8414 | 0:f479e4f4db0e | 120 | // status code will be returned. And the content is only parsed when |
| jb8414 | 0:f479e4f4db0e | 121 | // the status code is 200. |
| citrusbyte | 13:0d574742208f | 122 | int listStreamValues(const char* deviceId, const char* streamName, |
| citrusbyte | 13:0d574742208f | 123 | stream_value_read_callback callback, void* context, |
| citrusbyte | 13:0d574742208f | 124 | const char* query = NULL); |
| jb8414 | 0:f479e4f4db0e | 125 | |
| jb8414 | 0:f479e4f4db0e | 126 | // Update datasource location |
| jb8414 | 0:f479e4f4db0e | 127 | // NOTE: On an Arduino Uno and other ATMEGA based boards, double has |
| jb8414 | 0:f479e4f4db0e | 128 | // 4-byte (32 bits) precision, which is the same as float. So there's |
| jb8414 | 0:f479e4f4db0e | 129 | // no natural double-precision floating number on these boards. With |
| jb8414 | 0:f479e4f4db0e | 130 | // a float value, we have a precision of roughly 7 digits, that means |
| jb8414 | 0:f479e4f4db0e | 131 | // either 5 or 6 digits after the floating point. According to wikipedia, |
| jb8414 | 0:f479e4f4db0e | 132 | // a difference of 0.00001 will give us ~1.1132m distance. If this |
| jb8414 | 0:f479e4f4db0e | 133 | // precision is good for you, you can use the double-version we provided |
| jb8414 | 0:f479e4f4db0e | 134 | // here. Otherwise, you may need to use the string-version and do the |
| jb8414 | 0:f479e4f4db0e | 135 | // actual conversion by yourselves. |
| jb8414 | 0:f479e4f4db0e | 136 | // However, with an Arduino Due board, double has 8-bytes (64 bits) |
| jb8414 | 0:f479e4f4db0e | 137 | // precision, which means you are free to use the double-version only |
| jb8414 | 0:f479e4f4db0e | 138 | // without any precision problems. |
| jb8414 | 0:f479e4f4db0e | 139 | // Returned value is the http status code. |
| jb8414 | 0:f479e4f4db0e | 140 | template <class T> |
| citrusbyte | 13:0d574742208f | 141 | int updateLocation(const char* deviceId, const char* name, |
| jb8414 | 0:f479e4f4db0e | 142 | T latitude, T longitude, T elevation); |
| jb8414 | 0:f479e4f4db0e | 143 | |
| citrusbyte | 13:0d574742208f | 144 | // Read location information for a device. Also used callback to process |
| jb8414 | 0:f479e4f4db0e | 145 | // data points for memory reasons. The HTTP status code is returned, |
| jb8414 | 0:f479e4f4db0e | 146 | // response is only parsed when the HTTP status code is 200 |
| citrusbyte | 13:0d574742208f | 147 | int readLocation(const char* deviceId, location_read_callback callback, |
| jb8414 | 0:f479e4f4db0e | 148 | void* context); |
| citrusbyte | 10:4ce9eba38dbe | 149 | |
| citrusbyte | 10:4ce9eba38dbe | 150 | // Delete values from a data stream |
| citrusbyte | 10:4ce9eba38dbe | 151 | // You will need to provide from and end date/time strings in the ISO8601 |
| citrusbyte | 10:4ce9eba38dbe | 152 | // format "yyyy-mm-ddTHH:MM:SS.SSSZ" where |
| citrusbyte | 10:4ce9eba38dbe | 153 | // yyyy: the year |
| citrusbyte | 10:4ce9eba38dbe | 154 | // mm: the month |
| citrusbyte | 10:4ce9eba38dbe | 155 | // dd: the day |
| citrusbyte | 10:4ce9eba38dbe | 156 | // HH: the hour (24 hour format) |
| citrusbyte | 10:4ce9eba38dbe | 157 | // MM: the minute |
| citrusbyte | 10:4ce9eba38dbe | 158 | // SS.SSS: the seconds (to the millisecond) |
| citrusbyte | 10:4ce9eba38dbe | 159 | // NOTE: the time is given in Zulu (GMT) |
| citrusbyte | 10:4ce9eba38dbe | 160 | // M2X will delete all values within the from to end date/time range. |
| citrusbyte | 10:4ce9eba38dbe | 161 | // The status code is 204 on success and 400 on a bad request (e.g. the |
| citrusbyte | 10:4ce9eba38dbe | 162 | // timestamp is not in ISO8601 format or the from timestamp is not less than |
| citrusbyte | 10:4ce9eba38dbe | 163 | // or equal to the end timestamp. |
| citrusbyte | 13:0d574742208f | 164 | int deleteValues(const char* deviceId, const char* streamName, |
| citrusbyte | 10:4ce9eba38dbe | 165 | const char* from, const char* end); |
| jb8414 | 0:f479e4f4db0e | 166 | private: |
| jb8414 | 0:f479e4f4db0e | 167 | Client* _client; |
| jb8414 | 0:f479e4f4db0e | 168 | const char* _key; |
| jb8414 | 0:f479e4f4db0e | 169 | int _case_insensitive; |
| jb8414 | 0:f479e4f4db0e | 170 | const char* _host; |
| jb8414 | 0:f479e4f4db0e | 171 | int _port; |
| jb8414 | 0:f479e4f4db0e | 172 | NullPrint _null_print; |
| jb8414 | 0:f479e4f4db0e | 173 | |
| jb8414 | 0:f479e4f4db0e | 174 | // Writes the HTTP header part for updating a stream value |
| citrusbyte | 13:0d574742208f | 175 | void writePutHeader(const char* deviceId, |
| citrusbyte | 10:4ce9eba38dbe | 176 | const char* streamName, |
| citrusbyte | 10:4ce9eba38dbe | 177 | int contentLength); |
| citrusbyte | 10:4ce9eba38dbe | 178 | // Writes the HTTP header part for deleting stream values |
| citrusbyte | 13:0d574742208f | 179 | void writeDeleteHeader(const char* deviceId, |
| citrusbyte | 10:4ce9eba38dbe | 180 | const char* streamName, |
| citrusbyte | 10:4ce9eba38dbe | 181 | int contentLength); |
| jb8414 | 0:f479e4f4db0e | 182 | // Writes HTTP header lines including M2X API Key, host, content |
| jb8414 | 0:f479e4f4db0e | 183 | // type and content length(if the body exists) |
| jb8414 | 0:f479e4f4db0e | 184 | void writeHttpHeader(int contentLength); |
| jb8414 | 0:f479e4f4db0e | 185 | // Parses HTTP response header and return the content length. |
| jb8414 | 0:f479e4f4db0e | 186 | // Note that this function does not parse all http headers, as long |
| jb8414 | 0:f479e4f4db0e | 187 | // as the content length is found, this function will return |
| jb8414 | 0:f479e4f4db0e | 188 | int readContentLength(); |
| jb8414 | 0:f479e4f4db0e | 189 | // Skips all HTTP response header part. Return minus value in case |
| jb8414 | 0:f479e4f4db0e | 190 | // the connection is closed before we got all headers |
| jb8414 | 0:f479e4f4db0e | 191 | int skipHttpHeader(); |
| jb8414 | 0:f479e4f4db0e | 192 | // Parses and returns the HTTP status code, note this function will |
| jb8414 | 0:f479e4f4db0e | 193 | // return immediately once it gets the status code |
| jb8414 | 0:f479e4f4db0e | 194 | int readStatusCode(bool closeClient); |
| jb8414 | 0:f479e4f4db0e | 195 | // Waits for a certain string pattern in the HTTP header, and returns |
| jb8414 | 0:f479e4f4db0e | 196 | // once the pattern is found. In the pattern, you can use '*' to denote |
| jb8414 | 0:f479e4f4db0e | 197 | // any character |
| jb8414 | 0:f479e4f4db0e | 198 | int waitForString(const char* str); |
| jb8414 | 0:f479e4f4db0e | 199 | // Closes the connection |
| jb8414 | 0:f479e4f4db0e | 200 | void close(); |
| jb8414 | 0:f479e4f4db0e | 201 | // Parses JSON response of stream value API, and calls callback function |
| jb8414 | 0:f479e4f4db0e | 202 | // once we get a data point |
| jb8414 | 0:f479e4f4db0e | 203 | int readStreamValue(stream_value_read_callback callback, void* context); |
| jb8414 | 0:f479e4f4db0e | 204 | // Parses JSON response of location API, and calls callback function once |
| jb8414 | 0:f479e4f4db0e | 205 | // we get a data point |
| jb8414 | 0:f479e4f4db0e | 206 | int readLocation(location_read_callback callback, void* context); |
| jb8414 | 0:f479e4f4db0e | 207 | }; |
| jb8414 | 0:f479e4f4db0e | 208 | |
| jb8414 | 0:f479e4f4db0e | 209 | #include "M2XStreamClient_template.h" |
| jb8414 | 0:f479e4f4db0e | 210 | |
| jb8414 | 0:f479e4f4db0e | 211 | #endif /* M2XStreamClient_h */ |
