Skip to content

Commit f2ff9ba

Browse files
committed
Version 2 of the Library. Now supporting streaming resources to websockets!! Required for real-time dashboards.
1 parent efadada commit f2ff9ba

File tree

8 files changed

+280
-72
lines changed

8 files changed

+280
-72
lines changed

library.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
name=thinger.io
2-
version=1.1.1
2+
version=2.0.0
33
author=Alvaro Luis Bustamante <[email protected]>
44
maintainer=Thinger.io <[email protected]>
55
sentence=Arduino library for the thinger.io IoT platform.
6-
paragraph=Thinger.io is an open source platform for the Internet of Things. It will allow easily connecting your things or devices for remote sensing and actuating. Working with several devices like ESP8266, Arduino Ethernet, Arduino Wifi, Arduino Yun, Adafruit CC3000, Texas Instruments CC3200.
6+
paragraph=Thinger.io is an open source platform for the Internet of Things. It will allow connecting your things or devices for remote sensing and actuating. Working with several devices like ESP8266, Arduino Ethernet, Arduino Wifi, Arduino Yun, Adafruit CC3000, Texas Instruments CC3200.
77
category=Communication
88
url=https://github.com/thinger-io/Arduino-Library
99
architectures=*

src/ThingerWifi.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class ThingerWifi : public ThingerClient {
7878

7979
public:
8080

81-
void add_wifi(char* ssid, char* password)
81+
void add_wifi(const char* ssid, const char* password)
8282
{
8383
wifi_ssid_ = ssid;
8484
wifi_password_ = password;
@@ -87,8 +87,8 @@ class ThingerWifi : public ThingerClient {
8787
private:
8888

8989
WiFiClient client_;
90-
char* wifi_ssid_;
91-
char* wifi_password_;
90+
const char* wifi_ssid_;
91+
const char* wifi_password_;
9292
};
9393

9494
#endif

src/thinger/pson.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,29 @@ namespace protoson {
156156
clear();
157157
}
158158

159+
size_t size() const{
160+
size_t size = 0;
161+
list_item* current = item_;
162+
while(current!=NULL){
163+
current = current->next_;
164+
size++;
165+
}
166+
return size;
167+
}
168+
169+
T* operator[](size_t index){
170+
list_item* current = item_;
171+
size_t current_index = 0;
172+
while(current!=NULL){
173+
if(current_index==index){
174+
return &current->item_;
175+
}
176+
current = current->next_;
177+
current_index++;
178+
}
179+
return NULL;
180+
}
181+
159182
void clear(){
160183
list_item* current = item_;
161184
while(current!=NULL){

src/thinger/thinger.h

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,27 @@ namespace thinger{
6363
/**
6464
* Can be override to start reconnection process
6565
*/
66-
virtual void disconnected(){}
66+
virtual void disconnected(){
67+
// stop all streaming resources after disconnect
68+
if(thinger_resource::get_streaming_counter()>0) {
69+
thinger_map<thinger_resource>::entry* current = resources_.begin();
70+
while(current!=NULL){
71+
current->value_.disable_streaming();
72+
current = current->next_;
73+
}
74+
}
75+
}
76+
77+
/**
78+
* Stream a given resource
79+
*/
80+
void stream_resource(thinger_resource& resource, thinger_message::signal_flag type){
81+
thinger_message message;
82+
message.set_stream_id(resource.get_stream_id());
83+
message.set_signal_flag(type);
84+
resource.fill_api_io(message.get_data());
85+
send_message(message);
86+
}
6787

6888
public:
6989

@@ -77,7 +97,8 @@ namespace thinger{
7797
keep_alive_response = true;
7898

7999
thinger_message message;
80-
message.resources().add("login").add(username).add(device_id).add(credential);
100+
message.set_signal_flag(thinger_message::AUTH);
101+
message.resources().add(username).add(device_id).add(credential);
81102
if(!send_message(message)) return false;
82103

83104
thinger_message response;
@@ -86,22 +107,44 @@ namespace thinger{
86107

87108
bool call_endpoint(const char* endpoint_name){
88109
thinger_message message;
89-
message.resources().add("ep").add(endpoint_name);
110+
message.set_signal_flag(thinger_message::CALL_ENDPOINT);
111+
message.resources().add(endpoint_name);
90112
return send_message(message);
91113
}
92114

93115
bool call_endpoint(const char* endpoint_name, pson& data){
94116
thinger_message message;
117+
message.set_signal_flag(thinger_message::CALL_ENDPOINT);
95118
message.set_data(data);
96-
message.resources().add("ep").add(endpoint_name);
119+
message.resources().add(endpoint_name);
97120
return send_message(message);
98121
}
99122

123+
bool call_endpoint(const char* endpoint_name, thinger_resource& resource){
124+
thinger_message message;
125+
message.set_signal_flag(thinger_message::CALL_ENDPOINT);
126+
message.resources().add(endpoint_name);
127+
resource.fill_api_io(message.get_data());
128+
return send_message(message);
129+
}
130+
131+
/**
132+
* Stream the given resource. This resource should be previously requested by an external process.
133+
* Otherwise, the resource will not be streamed as nothing will be listening for it.
134+
*/
135+
bool stream(thinger_resource& resource){
136+
if(resource.stream_enabled()){
137+
stream_resource(resource, thinger_message::STREAM_EVENT);
138+
return true;
139+
}
140+
return false;
141+
}
142+
100143
bool send_message(thinger_message& message)
101144
{
102145
thinger_encoder sink;
103146
sink.encode(message);
104-
encoder.pb_encode_varint(message.get_message_type());
147+
encoder.pb_encode_varint(MESSAGE);
105148
encoder.pb_encode_varint(sink.bytes_written());
106149
encoder.encode(message);
107150
return write(NULL, 0, true);
@@ -119,24 +162,35 @@ namespace thinger{
119162
if(keep_alive_response){
120163
last_keep_alive = current_time;
121164
keep_alive_response = false;
122-
encoder.pb_encode_varint(thinger_message::KEEP_ALIVE);
165+
encoder.pb_encode_varint(KEEP_ALIVE);
123166
encoder.pb_encode_varint(0);
124167
write(NULL, 0, true);
125168
}else{
126169
disconnected();
127170
}
128171
}
172+
173+
// handle streaming resources
174+
if(thinger_resource::get_streaming_counter()>0){
175+
thinger_map<thinger_resource>::entry* current = resources_.begin();
176+
while(current!=NULL){
177+
if(current->value_.stream_required(current_time)){
178+
stream_resource(current->value_, thinger_message::STREAM_SAMPLE);
179+
}
180+
current = current->next_;
181+
}
182+
}
129183
}
130184

131185
bool read_message(thinger_message& message){
132-
uint8_t message_type = decoder.pb_decode_varint32();
133-
switch (message_type){
134-
case thinger_message::MESSAGE: {
186+
uint8_t type = decoder.pb_decode_varint32();
187+
switch (type){
188+
case MESSAGE: {
135189
size_t size = decoder.pb_decode_varint32();
136190
decoder.decode(message, size);
137191
}
138192
break;
139-
case thinger_message::KEEP_ALIVE: {
193+
case KEEP_ALIVE: {
140194
size_t size = decoder.pb_decode_varint32();
141195
keep_alive_response = true;
142196
}

src/thinger/thinger_decoder.hpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@ namespace thinger{
4343
uint32_t size = pb_decode_varint32();
4444
void *data = NULL;
4545
switch (field_number) {
46+
/*
4647
case thinger_message::THING_ID:
4748
data = protoson::pool.allocate(size + 1);
4849
pb_read_string((char *) data, size);
4950
message.set_thing_id((const char *) data);
5051
break;
52+
*/
5153
default:
5254
pb_skip(size);
5355
break;
@@ -73,7 +75,7 @@ namespace thinger{
7375
case thinger_message::RESOURCE:
7476
protoson::pson_decoder::decode(message.get_resources());
7577
break;
76-
case thinger_message::PSON:
78+
case thinger_message::PSON_PAYLOAD:
7779
protoson::pson_decoder::decode(((protoson::pson&) message));
7880
break;
7981
default:
@@ -116,8 +118,12 @@ namespace thinger{
116118

117119
protected:
118120
virtual bool read(void* buffer, size_t size){
119-
memcpy(buffer, buffer_ + read_, size);
120-
return protoson::pson_decoder::read(buffer, size);
121+
if(read_+size<=size_){
122+
memcpy(buffer, buffer_ + read_, size);
123+
return protoson::pson_decoder::read(buffer, size);
124+
}else{
125+
return false;
126+
}
121127
}
122128

123129
private:

src/thinger/thinger_encoder.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,12 @@ class thinger_encoder : public protoson::pson_encoder{
4444
if(message.get_signal_flag()!=thinger_message::NONE){
4545
pb_encode_varint(thinger_message::SIGNAL_FLAG, message.get_signal_flag());
4646
}
47-
if(message.get_thing_id()!=NULL){
48-
pb_encode_string(message.get_thing_id(), thinger_message::THING_ID);
49-
}
5047
if(message.has_resource()){
5148
pb_encode_tag(protoson::pson_type, thinger_message::RESOURCE);
5249
protoson::pson_encoder::encode(message.get_resources());
5350
}
5451
if(message.has_data()){
55-
pb_encode_tag(protoson::pson_type, thinger_message::PSON);
52+
pb_encode_tag(protoson::pson_type, thinger_message::PSON_PAYLOAD);
5653
protoson::pson_encoder::encode((protoson::pson&) message);
5754
}
5855
}

src/thinger/thinger_message.hpp

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -28,55 +28,99 @@
2828

2929
namespace thinger{
3030

31+
enum message_type{
32+
MESSAGE = 1,
33+
KEEP_ALIVE = 2
34+
};
35+
3136
class thinger_message{
37+
3238
public:
33-
enum message_type{ MESSAGE = 1, KEEP_ALIVE = 2 };
34-
enum signal_flag { NONE=0, REQUEST_OK = 1, REQUEST_ERROR = 2 };
35-
enum fields{ STREAM_ID = 1, SIGNAL_FLAG = 2, THING_ID = 3, RESOURCE = 4, ACTION = 5, PSON = 6};
39+
40+
// fields for a thinger message (encoded as in protocol buffers)
41+
enum fields{
42+
STREAM_ID = 1,
43+
SIGNAL_FLAG = 2,
44+
UNUSED = 3,
45+
RESOURCE = 4,
46+
UNUSED2 = 5,
47+
PSON_PAYLOAD = 6
48+
};
49+
50+
// flags for describing a thinger message
51+
enum signal_flag {
52+
// GENERAL USED FLAGS
53+
REQUEST_OK = 1, // the request with the given stream id was successful
54+
REQUEST_ERROR = 2, // the request with the given stream id failed
55+
56+
// SENT BY THE SERVER
57+
NONE = 0, // default resource action: just execute the given resource
58+
START_STREAM = 3, // enable a streaming resource (with stream_id, and resource filled, sample interval (in payload) is optional)
59+
STOP_STREAM = 4, // stop the streaming resource (with stream_id, and resource filled)
60+
61+
// SENT BY DEVICE
62+
AUTH = 5,
63+
STREAM_EVENT = 6, // means that the message data is related to a stream event
64+
STREAM_SAMPLE = 7, // means that the message is related to a periodical streaming sample
65+
CALL_ENDPOINT = 8 // call the endpoint with the provided name (endpoint in resource, value passed in payload)
66+
};
3667

3768
public:
3869

39-
thinger_message(thinger_message& other) : message_type_(other.message_type_), stream_id(other.stream_id), flag(REQUEST_OK), thing_id(NULL), resource(NULL), data(NULL), data_allocated(false){
40-
}
70+
/**
71+
* Initialize a default response message setting the same stream id of the source message,
72+
* and initializing the signal flag to ok. All remaining data or fields are empty
73+
*/
74+
thinger_message(thinger_message& other) :
75+
stream_id(other.stream_id),
76+
flag(REQUEST_OK),
77+
resource(NULL),
78+
data(NULL),
79+
data_allocated(false)
80+
{}
4181

42-
thinger_message() : message_type_(MESSAGE), stream_id(0), flag(NONE), thing_id(NULL), resource(NULL), data(NULL), data_allocated(false)
82+
/**
83+
* Initialize a default empty message
84+
*/
85+
thinger_message() :
86+
stream_id(0),
87+
flag(NONE),
88+
resource(NULL),
89+
data(NULL),
90+
data_allocated(false)
4391
{}
4492

4593
~thinger_message(){
46-
protoson::pool.deallocate(thing_id);
94+
// deallocate resource
4795
destroy(resource, protoson::pool);
96+
// deallocate paylaod if was allocated here
4897
if(data_allocated){
4998
destroy(data, protoson::pool);
5099
}
51100
}
52101

53102
private:
54-
message_type message_type_;
55-
uint32_t stream_id;
103+
/// used for identifying a unique stream
104+
uint16_t stream_id;
105+
/// used for setting a stream signal
56106
signal_flag flag;
57-
char* thing_id;
107+
/// used to identify a device resource
58108
protoson::pson* resource;
109+
/// used to fill a data payload in the message
59110
protoson::pson* data;
111+
/// flag to determine when the payload has been reserved
60112
bool data_allocated;
61113

62114
public:
63115

64-
message_type get_message_type(){
65-
return message_type_;
66-
}
67-
68-
uint32_t get_stream_id(){
116+
uint16_t get_stream_id(){
69117
return stream_id;
70118
}
71119

72120
signal_flag get_signal_flag(){
73121
return flag;
74122
}
75123

76-
const char* get_thing_id(){
77-
return thing_id;
78-
}
79-
80124
bool has_data(){
81125
return data!=NULL;
82126
}
@@ -86,24 +130,14 @@ namespace thinger{
86130
}
87131

88132
public:
89-
void set_stream_id(uint32_t stream_id) {
133+
void set_stream_id(uint16_t stream_id) {
90134
thinger_message::stream_id = stream_id;
91135
}
92136

93137
void set_signal_flag(signal_flag const &flag) {
94138
thinger_message::flag = flag;
95139
}
96140

97-
void set_thing_id(const char *thing_id) {
98-
size_t str_size = strlen(thing_id);
99-
this->thing_id = (char*)protoson::pool.allocate(str_size+1);
100-
memcpy(this->thing_id, thing_id, str_size+1);
101-
}
102-
103-
void set_message_type(message_type type){
104-
message_type_ = type;
105-
}
106-
107141
public:
108142

109143
void operator=(const char* str){

0 commit comments

Comments
 (0)