Browse Source

Add Roomba code

master
Steven Haigh 4 months ago
parent
commit
2384861c2e
27 changed files with 2504 additions and 0 deletions
  1. BIN
      Roomba/iRobot_Roomba_600_Open_Interface_Spec.pdf
  2. 1
    0
      Roomba/lib/PubSubClient_ID89/.gitignore
  3. 35
    0
      Roomba/lib/PubSubClient_ID89/.library.json
  4. 7
    0
      Roomba/lib/PubSubClient_ID89/.travis.yml
  5. 76
    0
      Roomba/lib/PubSubClient_ID89/CHANGES.txt
  6. 20
    0
      Roomba/lib/PubSubClient_ID89/LICENSE.txt
  7. 48
    0
      Roomba/lib/PubSubClient_ID89/README.md
  8. 43
    0
      Roomba/lib/PubSubClient_ID89/examples/mqtt_auth/mqtt_auth.ino
  9. 77
    0
      Roomba/lib/PubSubClient_ID89/examples/mqtt_basic/mqtt_basic.ino
  10. 132
    0
      Roomba/lib/PubSubClient_ID89/examples/mqtt_esp8266/mqtt_esp8266.ino
  11. 179
    0
      Roomba/lib/PubSubClient_ID89/examples/mqtt_large_message/mqtt_large_message.ino
  12. 60
    0
      Roomba/lib/PubSubClient_ID89/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino
  13. 67
    0
      Roomba/lib/PubSubClient_ID89/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino
  14. 57
    0
      Roomba/lib/PubSubClient_ID89/examples/mqtt_stream/mqtt_stream.ino
  15. 33
    0
      Roomba/lib/PubSubClient_ID89/keywords.txt
  16. 17
    0
      Roomba/lib/PubSubClient_ID89/library.json
  17. 9
    0
      Roomba/lib/PubSubClient_ID89/library.properties
  18. 653
    0
      Roomba/lib/PubSubClient_ID89/src/PubSubClient.cpp
  19. 173
    0
      Roomba/lib/PubSubClient_ID89/src/PubSubClient.h
  20. 0
    0
      Roomba/lib/SimpleTimer_ID419/.gitignore
  21. 27
    0
      Roomba/lib/SimpleTimer_ID419/.library.json
  22. 2
    0
      Roomba/lib/SimpleTimer_ID419/README
  23. 241
    0
      Roomba/lib/SimpleTimer_ID419/SimpleTimer.cpp
  24. 124
    0
      Roomba/lib/SimpleTimer_ID419/SimpleTimer.h
  25. 12
    0
      Roomba/lib/SimpleTimer_ID419/library.json
  26. 20
    0
      Roomba/platformio.ini
  27. 391
    0
      Roomba/src/Roomba.ino

BIN
Roomba/iRobot_Roomba_600_Open_Interface_Spec.pdf View File


+ 1
- 0
Roomba/lib/PubSubClient_ID89/.gitignore View File

@@ -0,0 +1 @@
1
+tests/bin

+ 35
- 0
Roomba/lib/PubSubClient_ID89/.library.json View File

@@ -0,0 +1,35 @@
1
+{
2
+    "name": "PubSubClient", 
3
+    "keywords": [
4
+        "ethernet", 
5
+        "mqtt", 
6
+        "m2m", 
7
+        "iot"
8
+    ], 
9
+    "description": "A client library for MQTT messaging. MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000.", 
10
+    "repository": {
11
+        "type": "git", 
12
+        "url": "https://github.com/knolleary/pubsubclient.git"
13
+    }, 
14
+    "version": "2.7", 
15
+    "examples": "examples/*/*.ino", 
16
+    "frameworks": [
17
+        "arduino"
18
+    ], 
19
+    "platforms": [
20
+        "atmelavr", 
21
+        "espressif8266"
22
+    ], 
23
+    "export": {
24
+        "exclude": "tests"
25
+    }, 
26
+    "authors": [
27
+        {
28
+            "email": "nick.oleary@gmail.com", 
29
+            "url": "https://github.com/knolleary", 
30
+            "maintainer": false, 
31
+            "name": "Nick O'Leary"
32
+        }
33
+    ], 
34
+    "id": 89
35
+}

+ 7
- 0
Roomba/lib/PubSubClient_ID89/.travis.yml View File

@@ -0,0 +1,7 @@
1
+sudo: false
2
+language: cpp
3
+compiler:
4
+  - g++
5
+script: cd tests && make && make test
6
+os:
7
+  - linux

+ 76
- 0
Roomba/lib/PubSubClient_ID89/CHANGES.txt View File

@@ -0,0 +1,76 @@
1
+2.7
2
+   * Fix remaining-length handling to prevent buffer overrun
3
+   * Add large-payload API - beginPublish/write/publish/endPublish
4
+   * Add yield call to improve reliability on ESP
5
+   * Add Clean Session flag to connect options
6
+   * Add ESP32 support for functional callback signature
7
+   * Various other fixes
8
+
9
+2.4
10
+   * Add MQTT_SOCKET_TIMEOUT to prevent it blocking indefinitely
11
+     whilst waiting for inbound data
12
+   * Fixed return code when publishing >256 bytes
13
+
14
+2.3
15
+   * Add publish(topic,payload,retained) function
16
+
17
+2.2
18
+   * Change code layout to match Arduino Library reqs
19
+
20
+2.1
21
+   * Add MAX_TRANSFER_SIZE def to chunk messages if needed
22
+   * Reject topic/payloads that exceed MQTT_MAX_PACKET_SIZE
23
+
24
+2.0
25
+   * Add (and default to) MQTT 3.1.1 support
26
+   * Fix PROGMEM handling for Intel Galileo/ESP8266
27
+   * Add overloaded constructors for convenience
28
+   * Add chainable setters for server/callback/client/stream
29
+   * Add state function to return connack return code
30
+
31
+1.9
32
+   * Do not split MQTT packets over multiple calls to _client->write()
33
+   * API change: All constructors now require an instance of Client
34
+      to be passed in.
35
+   * Fixed example to match 1.8 api changes - dpslwk
36
+   * Added username/password support - WilHall
37
+   * Added publish_P - publishes messages from PROGMEM - jobytaffey
38
+
39
+1.8
40
+    * KeepAlive interval is configurable in PubSubClient.h
41
+    * Maximum packet size is configurable in PubSubClient.h
42
+    * API change: Return boolean rather than int from various functions
43
+    * API change: Length parameter in message callback changed
44
+       from int to unsigned int
45
+    * Various internal tidy-ups around types
46
+1.7
47
+    * Improved keepalive handling
48
+    * Updated to the Arduino-1.0 API
49
+1.6
50
+    * Added the ability to publish a retained message
51
+
52
+1.5
53
+    * Added default constructor
54
+    * Fixed compile error when used with arduino-0021 or later
55
+
56
+1.4
57
+    * Fixed connection lost handling
58
+
59
+1.3
60
+    * Fixed packet reading bug in PubSubClient.readPacket
61
+
62
+1.2
63
+    * Fixed compile error when used with arduino-0016 or later
64
+
65
+
66
+1.1
67
+    * Reduced size of library
68
+    * Added support for Will messages
69
+    * Clarified licensing - see LICENSE.txt
70
+
71
+
72
+1.0
73
+    * Only Quality of Service (QOS) 0 messaging is supported
74
+    * The maximum message size, including header, is 128 bytes
75
+    * The keepalive interval is set to 30 seconds
76
+    * No support for Will messages

+ 20
- 0
Roomba/lib/PubSubClient_ID89/LICENSE.txt View File

@@ -0,0 +1,20 @@
1
+Copyright (c) 2008-2015 Nicholas O'Leary
2
+
3
+Permission is hereby granted, free of charge, to any person obtaining
4
+a copy of this software and associated documentation files (the
5
+"Software"), to deal in the Software without restriction, including
6
+without limitation the rights to use, copy, modify, merge, publish,
7
+distribute, sublicense, and/or sell copies of the Software, and to
8
+permit persons to whom the Software is furnished to do so, subject to
9
+the following conditions:
10
+
11
+The above copyright notice and this permission notice shall be
12
+included in all copies or substantial portions of the Software.
13
+
14
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 48
- 0
Roomba/lib/PubSubClient_ID89/README.md View File

@@ -0,0 +1,48 @@
1
+# Arduino Client for MQTT
2
+
3
+This library provides a client for doing simple publish/subscribe messaging with
4
+a server that supports MQTT.
5
+
6
+## Examples
7
+
8
+The library comes with a number of example sketches. See File > Examples > PubSubClient
9
+within the Arduino application.
10
+
11
+Full API documentation is available here: https://pubsubclient.knolleary.net
12
+
13
+## Limitations
14
+
15
+ - It can only publish QoS 0 messages. It can subscribe at QoS 0 or QoS 1.
16
+ - The maximum message size, including header, is **128 bytes** by default. This
17
+   is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h`.
18
+ - The keepalive interval is set to 15 seconds by default. This is configurable
19
+   via `MQTT_KEEPALIVE` in `PubSubClient.h`.
20
+ - The client uses MQTT 3.1.1 by default. It can be changed to use MQTT 3.1 by
21
+   changing value of `MQTT_VERSION` in `PubSubClient.h`.
22
+
23
+
24
+## Compatible Hardware
25
+
26
+The library uses the Arduino Ethernet Client api for interacting with the
27
+underlying network hardware. This means it Just Works with a growing number of
28
+boards and shields, including:
29
+
30
+ - Arduino Ethernet
31
+ - Arduino Ethernet Shield
32
+ - Arduino YUN – use the included `YunClient` in place of `EthernetClient`, and
33
+   be sure to do a `Bridge.begin()` first
34
+ - Arduino WiFi Shield - if you want to send packets > 90 bytes with this shield,
35
+   enable the `MQTT_MAX_TRANSFER_SIZE` define in `PubSubClient.h`.
36
+ - Sparkfun WiFly Shield – [library](https://github.com/dpslwk/WiFly)
37
+ - TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library)
38
+ - Intel Galileo/Edison
39
+ - ESP8266
40
+ - ESP32
41
+
42
+The library cannot currently be used with hardware based on the ENC28J60 chip –
43
+such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an
44
+[alternative library](https://github.com/njh/NanodeMQTT) available.
45
+
46
+## License
47
+
48
+This code is released under the MIT License.

+ 43
- 0
Roomba/lib/PubSubClient_ID89/examples/mqtt_auth/mqtt_auth.ino View File

@@ -0,0 +1,43 @@
1
+/*
2
+ Basic MQTT example with Authentication
3
+
4
+  - connects to an MQTT server, providing username
5
+    and password
6
+  - publishes "hello world" to the topic "outTopic"
7
+  - subscribes to the topic "inTopic"
8
+*/
9
+
10
+#include <SPI.h>
11
+#include <Ethernet.h>
12
+#include <PubSubClient.h>
13
+
14
+// Update these with values suitable for your network.
15
+byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
16
+IPAddress ip(172, 16, 0, 100);
17
+IPAddress server(172, 16, 0, 2);
18
+
19
+void callback(char* topic, byte* payload, unsigned int length) {
20
+  // handle message arrived
21
+}
22
+
23
+EthernetClient ethClient;
24
+PubSubClient client(server, 1883, callback, ethClient);
25
+
26
+void setup()
27
+{
28
+  Ethernet.begin(mac, ip);
29
+  // Note - the default maximum packet size is 128 bytes. If the
30
+  // combined length of clientId, username and password exceed this,
31
+  // you will need to increase the value of MQTT_MAX_PACKET_SIZE in
32
+  // PubSubClient.h
33
+  
34
+  if (client.connect("arduinoClient", "testuser", "testpass")) {
35
+    client.publish("outTopic","hello world");
36
+    client.subscribe("inTopic");
37
+  }
38
+}
39
+
40
+void loop()
41
+{
42
+  client.loop();
43
+}

+ 77
- 0
Roomba/lib/PubSubClient_ID89/examples/mqtt_basic/mqtt_basic.ino View File

@@ -0,0 +1,77 @@
1
+/*
2
+ Basic MQTT example
3
+
4
+ This sketch demonstrates the basic capabilities of the library.
5
+ It connects to an MQTT server then:
6
+  - publishes "hello world" to the topic "outTopic"
7
+  - subscribes to the topic "inTopic", printing out any messages
8
+    it receives. NB - it assumes the received payloads are strings not binary
9
+
10
+ It will reconnect to the server if the connection is lost using a blocking
11
+ reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
12
+ achieve the same result without blocking the main loop.
13
+ 
14
+*/
15
+
16
+#include <SPI.h>
17
+#include <Ethernet.h>
18
+#include <PubSubClient.h>
19
+
20
+// Update these with values suitable for your network.
21
+byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
22
+IPAddress ip(172, 16, 0, 100);
23
+IPAddress server(172, 16, 0, 2);
24
+
25
+void callback(char* topic, byte* payload, unsigned int length) {
26
+  Serial.print("Message arrived [");
27
+  Serial.print(topic);
28
+  Serial.print("] ");
29
+  for (int i=0;i<length;i++) {
30
+    Serial.print((char)payload[i]);
31
+  }
32
+  Serial.println();
33
+}
34
+
35
+EthernetClient ethClient;
36
+PubSubClient client(ethClient);
37
+
38
+void reconnect() {
39
+  // Loop until we're reconnected
40
+  while (!client.connected()) {
41
+    Serial.print("Attempting MQTT connection...");
42
+    // Attempt to connect
43
+    if (client.connect("arduinoClient")) {
44
+      Serial.println("connected");
45
+      // Once connected, publish an announcement...
46
+      client.publish("outTopic","hello world");
47
+      // ... and resubscribe
48
+      client.subscribe("inTopic");
49
+    } else {
50
+      Serial.print("failed, rc=");
51
+      Serial.print(client.state());
52
+      Serial.println(" try again in 5 seconds");
53
+      // Wait 5 seconds before retrying
54
+      delay(5000);
55
+    }
56
+  }
57
+}
58
+
59
+void setup()
60
+{
61
+  Serial.begin(57600);
62
+
63
+  client.setServer(server, 1883);
64
+  client.setCallback(callback);
65
+
66
+  Ethernet.begin(mac, ip);
67
+  // Allow the hardware to sort itself out
68
+  delay(1500);
69
+}
70
+
71
+void loop()
72
+{
73
+  if (!client.connected()) {
74
+    reconnect();
75
+  }
76
+  client.loop();
77
+}

+ 132
- 0
Roomba/lib/PubSubClient_ID89/examples/mqtt_esp8266/mqtt_esp8266.ino View File

@@ -0,0 +1,132 @@
1
+/*
2
+ Basic ESP8266 MQTT example
3
+
4
+ This sketch demonstrates the capabilities of the pubsub library in combination
5
+ with the ESP8266 board/library.
6
+
7
+ It connects to an MQTT server then:
8
+  - publishes "hello world" to the topic "outTopic" every two seconds
9
+  - subscribes to the topic "inTopic", printing out any messages
10
+    it receives. NB - it assumes the received payloads are strings not binary
11
+  - If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
12
+    else switch it off
13
+
14
+ It will reconnect to the server if the connection is lost using a blocking
15
+ reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
16
+ achieve the same result without blocking the main loop.
17
+
18
+ To install the ESP8266 board, (using Arduino 1.6.4+):
19
+  - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
20
+       http://arduino.esp8266.com/stable/package_esp8266com_index.json
21
+  - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
22
+  - Select your ESP8266 in "Tools -> Board"
23
+
24
+*/
25
+
26
+#include <ESP8266WiFi.h>
27
+#include <PubSubClient.h>
28
+
29
+// Update these with values suitable for your network.
30
+
31
+const char* ssid = "........";
32
+const char* password = "........";
33
+const char* mqtt_server = "broker.mqtt-dashboard.com";
34
+
35
+WiFiClient espClient;
36
+PubSubClient client(espClient);
37
+long lastMsg = 0;
38
+char msg[50];
39
+int value = 0;
40
+
41
+void setup_wifi() {
42
+
43
+  delay(10);
44
+  // We start by connecting to a WiFi network
45
+  Serial.println();
46
+  Serial.print("Connecting to ");
47
+  Serial.println(ssid);
48
+
49
+  WiFi.begin(ssid, password);
50
+
51
+  while (WiFi.status() != WL_CONNECTED) {
52
+    delay(500);
53
+    Serial.print(".");
54
+  }
55
+
56
+  randomSeed(micros());
57
+
58
+  Serial.println("");
59
+  Serial.println("WiFi connected");
60
+  Serial.println("IP address: ");
61
+  Serial.println(WiFi.localIP());
62
+}
63
+
64
+void callback(char* topic, byte* payload, unsigned int length) {
65
+  Serial.print("Message arrived [");
66
+  Serial.print(topic);
67
+  Serial.print("] ");
68
+  for (int i = 0; i < length; i++) {
69
+    Serial.print((char)payload[i]);
70
+  }
71
+  Serial.println();
72
+
73
+  // Switch on the LED if an 1 was received as first character
74
+  if ((char)payload[0] == '1') {
75
+    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
76
+    // but actually the LED is on; this is because
77
+    // it is active low on the ESP-01)
78
+  } else {
79
+    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
80
+  }
81
+
82
+}
83
+
84
+void reconnect() {
85
+  // Loop until we're reconnected
86
+  while (!client.connected()) {
87
+    Serial.print("Attempting MQTT connection...");
88
+    // Create a random client ID
89
+    String clientId = "ESP8266Client-";
90
+    clientId += String(random(0xffff), HEX);
91
+    // Attempt to connect
92
+    if (client.connect(clientId.c_str())) {
93
+      Serial.println("connected");
94
+      // Once connected, publish an announcement...
95
+      client.publish("outTopic", "hello world");
96
+      // ... and resubscribe
97
+      client.subscribe("inTopic");
98
+    } else {
99
+      Serial.print("failed, rc=");
100
+      Serial.print(client.state());
101
+      Serial.println(" try again in 5 seconds");
102
+      // Wait 5 seconds before retrying
103
+      delay(5000);
104
+    }
105
+  }
106
+}
107
+
108
+void setup() {
109
+  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
110
+  Serial.begin(115200);
111
+  setup_wifi();
112
+  client.setServer(mqtt_server, 1883);
113
+  client.setCallback(callback);
114
+}
115
+
116
+void loop() {
117
+
118
+  if (!client.connected()) {
119
+    reconnect();
120
+  }
121
+  client.loop();
122
+
123
+  long now = millis();
124
+  if (now - lastMsg > 2000) {
125
+    lastMsg = now;
126
+    ++value;
127
+    snprintf (msg, 50, "hello world #%ld", value);
128
+    Serial.print("Publish message: ");
129
+    Serial.println(msg);
130
+    client.publish("outTopic", msg);
131
+  }
132
+}

+ 179
- 0
Roomba/lib/PubSubClient_ID89/examples/mqtt_large_message/mqtt_large_message.ino View File

@@ -0,0 +1,179 @@
1
+/*
2
+ Long message ESP8266 MQTT example
3
+
4
+ This sketch demonstrates sending arbitrarily large messages in combination
5
+ with the ESP8266 board/library.
6
+
7
+ It connects to an MQTT server then:
8
+  - publishes "hello world" to the topic "outTopic"
9
+  - subscribes to the topic "greenBottles/#", printing out any messages
10
+    it receives. NB - it assumes the received payloads are strings not binary
11
+  - If the sub-topic is a number, it publishes a "greenBottles/lyrics" message
12
+    with a payload consisting of the lyrics to "10 green bottles", replacing
13
+    10 with the number given in the sub-topic.
14
+
15
+ It will reconnect to the server if the connection is lost using a blocking
16
+ reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
17
+ achieve the same result without blocking the main loop.
18
+
19
+ To install the ESP8266 board, (using Arduino 1.6.4+):
20
+  - Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
21
+       http://arduino.esp8266.com/stable/package_esp8266com_index.json
22
+  - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
23
+  - Select your ESP8266 in "Tools -> Board"
24
+
25
+*/
26
+
27
+#include <ESP8266WiFi.h>
28
+#include <PubSubClient.h>
29
+
30
+// Update these with values suitable for your network.
31
+
32
+const char* ssid = "........";
33
+const char* password = "........";
34
+const char* mqtt_server = "broker.mqtt-dashboard.com";
35
+
36
+WiFiClient espClient;
37
+PubSubClient client(espClient);
38
+long lastMsg = 0;
39
+char msg[50];
40
+int value = 0;
41
+
42
+void setup_wifi() {
43
+
44
+  delay(10);
45
+  // We start by connecting to a WiFi network
46
+  Serial.println();
47
+  Serial.print("Connecting to ");
48
+  Serial.println(ssid);
49
+
50
+  WiFi.begin(ssid, password);
51
+
52
+  while (WiFi.status() != WL_CONNECTED) {
53
+    delay(500);
54
+    Serial.print(".");
55
+  }
56
+
57
+  randomSeed(micros());
58
+
59
+  Serial.println("");
60
+  Serial.println("WiFi connected");
61
+  Serial.println("IP address: ");
62
+  Serial.println(WiFi.localIP());
63
+}
64
+
65
+void callback(char* topic, byte* payload, unsigned int length) {
66
+  Serial.print("Message arrived [");
67
+  Serial.print(topic);
68
+  Serial.print("] ");
69
+  for (int i = 0; i < length; i++) {
70
+    Serial.print((char)payload[i]);
71
+  }
72
+  Serial.println();
73
+
74
+  // Find out how many bottles we should generate lyrics for
75
+  String topicStr(topic);
76
+  int bottleCount = 0; // assume no bottles unless we correctly parse a value from the topic
77
+  if (topicStr.indexOf('/') >= 0) {
78
+    // The topic includes a '/', we'll try to read the number of bottles from just after that
79
+    topicStr.remove(0, topicStr.indexOf('/')+1);
80
+    // Now see if there's a number of bottles after the '/'
81
+    bottleCount = topicStr.toInt();
82
+  }
83
+
84
+  if (bottleCount > 0) {
85
+    // Work out how big our resulting message will be
86
+    int msgLen = 0;
87
+    for (int i = bottleCount; i > 0; i--) {
88
+      String numBottles(i);
89
+      msgLen += 2*numBottles.length();
90
+      if (i == 1) {
91
+        msgLen += 2*String(" green bottle, standing on the wall\n").length();
92
+      } else {
93
+        msgLen += 2*String(" green bottles, standing on the wall\n").length();
94
+      }
95
+      msgLen += String("And if one green bottle should accidentally fall\nThere'll be ").length();
96
+      switch (i) {
97
+      case 1:
98
+        msgLen += String("no green bottles, standing on the wall\n\n").length();
99
+        break;
100
+      case 2:
101
+        msgLen += String("1 green bottle, standing on the wall\n\n").length();
102
+        break;
103
+      default:
104
+        numBottles = i-1;
105
+        msgLen += numBottles.length();
106
+        msgLen += String(" green bottles, standing on the wall\n\n").length();
107
+        break;
108
+      };
109
+    }
110
+  
111
+    // Now we can start to publish the message
112
+    client.beginPublish("greenBottles/lyrics", msgLen, false);
113
+    for (int i = bottleCount; i > 0; i--) {
114
+      for (int j = 0; j < 2; j++) {
115
+        client.print(i);
116
+        if (i == 1) {
117
+          client.print(" green bottle, standing on the wall\n");
118
+        } else {
119
+          client.print(" green bottles, standing on the wall\n");
120
+        }
121
+      }
122
+      client.print("And if one green bottle should accidentally fall\nThere'll be ");
123
+      switch (i) {
124
+      case 1:
125
+        client.print("no green bottles, standing on the wall\n\n");
126
+        break;
127
+      case 2:
128
+        client.print("1 green bottle, standing on the wall\n\n");
129
+        break;
130
+      default:
131
+        client.print(i-1);
132
+        client.print(" green bottles, standing on the wall\n\n");
133
+        break;
134
+      };
135
+    }
136
+    // Now we're done!
137
+    client.endPublish();
138
+  }
139
+}
140
+
141
+void reconnect() {
142
+  // Loop until we're reconnected
143
+  while (!client.connected()) {
144
+    Serial.print("Attempting MQTT connection...");
145
+    // Create a random client ID
146
+    String clientId = "ESP8266Client-";
147
+    clientId += String(random(0xffff), HEX);
148
+    // Attempt to connect
149
+    if (client.connect(clientId.c_str())) {
150
+      Serial.println("connected");
151
+      // Once connected, publish an announcement...
152
+      client.publish("outTopic", "hello world");
153
+      // ... and resubscribe
154
+      client.subscribe("greenBottles/#");
155
+    } else {
156
+      Serial.print("failed, rc=");
157
+      Serial.print(client.state());
158
+      Serial.println(" try again in 5 seconds");
159
+      // Wait 5 seconds before retrying
160
+      delay(5000);
161
+    }
162
+  }
163
+}
164
+
165
+void setup() {
166
+  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
167
+  Serial.begin(115200);
168
+  setup_wifi();
169
+  client.setServer(mqtt_server, 1883);
170
+  client.setCallback(callback);
171
+}
172
+
173
+void loop() {
174
+
175
+  if (!client.connected()) {
176
+    reconnect();
177
+  }
178
+  client.loop();
179
+}

+ 60
- 0
Roomba/lib/PubSubClient_ID89/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino View File

@@ -0,0 +1,60 @@
1
+/*
2
+ Publishing in the callback
3
+
4
+  - connects to an MQTT server
5
+  - subscribes to the topic "inTopic"
6
+  - when a message is received, republishes it to "outTopic"
7
+
8
+  This example shows how to publish messages within the
9
+  callback function. The callback function header needs to
10
+  be declared before the PubSubClient constructor and the
11
+  actual callback defined afterwards.
12
+  This ensures the client reference in the callback function
13
+  is valid.
14
+
15
+*/
16
+
17
+#include <SPI.h>
18
+#include <Ethernet.h>
19
+#include <PubSubClient.h>
20
+
21
+// Update these with values suitable for your network.
22
+byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
23
+IPAddress ip(172, 16, 0, 100);
24
+IPAddress server(172, 16, 0, 2);
25
+
26
+// Callback function header
27
+void callback(char* topic, byte* payload, unsigned int length);
28
+
29
+EthernetClient ethClient;
30
+PubSubClient client(server, 1883, callback, ethClient);
31
+
32
+// Callback function
33
+void callback(char* topic, byte* payload, unsigned int length) {
34
+  // In order to republish this payload, a copy must be made
35
+  // as the orignal payload buffer will be overwritten whilst
36
+  // constructing the PUBLISH packet.
37
+
38
+  // Allocate the correct amount of memory for the payload copy
39
+  byte* p = (byte*)malloc(length);
40
+  // Copy the payload to the new buffer
41
+  memcpy(p,payload,length);
42
+  client.publish("outTopic", p, length);
43
+  // Free the memory
44
+  free(p);
45
+}
46
+
47
+void setup()
48
+{
49
+
50
+  Ethernet.begin(mac, ip);
51
+  if (client.connect("arduinoClient")) {
52
+    client.publish("outTopic","hello world");
53
+    client.subscribe("inTopic");
54
+  }
55
+}
56
+
57
+void loop()
58
+{
59
+  client.loop();
60
+}

+ 67
- 0
Roomba/lib/PubSubClient_ID89/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino View File

@@ -0,0 +1,67 @@
1
+/*
2
+ Reconnecting MQTT example - non-blocking
3
+
4
+ This sketch demonstrates how to keep the client connected
5
+ using a non-blocking reconnect function. If the client loses
6
+ its connection, it attempts to reconnect every 5 seconds
7
+ without blocking the main loop.
8
+
9
+*/
10
+
11
+#include <SPI.h>
12
+#include <Ethernet.h>
13
+#include <PubSubClient.h>
14
+
15
+// Update these with values suitable for your hardware/network.
16
+byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
17
+IPAddress ip(172, 16, 0, 100);
18
+IPAddress server(172, 16, 0, 2);
19
+
20
+void callback(char* topic, byte* payload, unsigned int length) {
21
+  // handle message arrived
22
+}
23
+
24
+EthernetClient ethClient;
25
+PubSubClient client(ethClient);
26
+
27
+long lastReconnectAttempt = 0;
28
+
29
+boolean reconnect() {
30
+  if (client.connect("arduinoClient")) {
31
+    // Once connected, publish an announcement...
32
+    client.publish("outTopic","hello world");
33
+    // ... and resubscribe
34
+    client.subscribe("inTopic");
35
+  }
36
+  return client.connected();
37
+}
38
+
39
+void setup()
40
+{
41
+  client.setServer(server, 1883);
42
+  client.setCallback(callback);
43
+
44
+  Ethernet.begin(mac, ip);
45
+  delay(1500);
46
+  lastReconnectAttempt = 0;
47
+}
48
+
49
+
50
+void loop()
51
+{
52
+  if (!client.connected()) {
53
+    long now = millis();
54
+    if (now - lastReconnectAttempt > 5000) {
55
+      lastReconnectAttempt = now;
56
+      // Attempt to reconnect
57
+      if (reconnect()) {
58
+        lastReconnectAttempt = 0;
59
+      }
60
+    }
61
+  } else {
62
+    // Client connected
63
+
64
+    client.loop();
65
+  }
66
+
67
+}

+ 57
- 0
Roomba/lib/PubSubClient_ID89/examples/mqtt_stream/mqtt_stream.ino View File

@@ -0,0 +1,57 @@
1
+/*
2
+ Example of using a Stream object to store the message payload
3
+
4
+ Uses SRAM library: https://github.com/ennui2342/arduino-sram
5
+ but could use any Stream based class such as SD
6
+
7
+  - connects to an MQTT server
8
+  - publishes "hello world" to the topic "outTopic"
9
+  - subscribes to the topic "inTopic"
10
+*/
11
+
12
+#include <SPI.h>
13
+#include <Ethernet.h>
14
+#include <PubSubClient.h>
15
+#include <SRAM.h>
16
+
17
+// Update these with values suitable for your network.
18
+byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
19
+IPAddress ip(172, 16, 0, 100);
20
+IPAddress server(172, 16, 0, 2);
21
+
22
+SRAM sram(4, SRAM_1024);
23
+
24
+void callback(char* topic, byte* payload, unsigned int length) {
25
+  sram.seek(1);
26
+
27
+  // do something with the message
28
+  for(uint8_t i=0; i<length; i++) {
29
+    Serial.write(sram.read());
30
+  }
31
+  Serial.println();
32
+
33
+  // Reset position for the next message to be stored
34
+  sram.seek(1);
35
+}
36
+
37
+EthernetClient ethClient;
38
+PubSubClient client(server, 1883, callback, ethClient, sram);
39
+
40
+void setup()
41
+{
42
+  Ethernet.begin(mac, ip);
43
+  if (client.connect("arduinoClient")) {
44
+    client.publish("outTopic","hello world");
45
+    client.subscribe("inTopic");
46
+  }
47
+
48
+  sram.begin();
49
+  sram.seek(1);
50
+
51
+  Serial.begin(9600);
52
+}
53
+
54
+void loop()
55
+{
56
+  client.loop();
57
+}

+ 33
- 0
Roomba/lib/PubSubClient_ID89/keywords.txt View File

@@ -0,0 +1,33 @@
1
+#######################################
2
+# Syntax Coloring Map For PubSubClient
3
+#######################################
4
+
5
+#######################################
6
+# Datatypes (KEYWORD1)
7
+#######################################
8
+
9
+PubSubClient	KEYWORD1
10
+
11
+#######################################
12
+# Methods and Functions (KEYWORD2)
13
+#######################################
14
+
15
+connect 	KEYWORD2
16
+disconnect 	KEYWORD2
17
+publish 	KEYWORD2
18
+publish_P 	KEYWORD2
19
+beginPublish 	KEYWORD2
20
+endPublish 	KEYWORD2
21
+write	 	KEYWORD2
22
+subscribe 	KEYWORD2
23
+unsubscribe 	KEYWORD2
24
+loop 	KEYWORD2
25
+connected 	KEYWORD2
26
+setServer	KEYWORD2
27
+setCallback	KEYWORD2
28
+setClient	KEYWORD2
29
+setStream	KEYWORD2
30
+
31
+#######################################
32
+# Constants (LITERAL1)
33
+#######################################

+ 17
- 0
Roomba/lib/PubSubClient_ID89/library.json View File

@@ -0,0 +1,17 @@
1
+{
2
+    "name": "PubSubClient",
3
+    "keywords": "ethernet, mqtt, m2m, iot",
4
+    "description": "A client library for MQTT messaging. MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000.",
5
+    "repository": {
6
+        "type": "git",
7
+        "url": "https://github.com/knolleary/pubsubclient.git"
8
+    },
9
+    "version": "2.7",
10
+    "exclude": "tests",
11
+    "examples": "examples/*/*.ino",
12
+    "frameworks": "arduino",
13
+    "platforms": [
14
+        "atmelavr",
15
+        "espressif"
16
+    ]
17
+}

+ 9
- 0
Roomba/lib/PubSubClient_ID89/library.properties View File

@@ -0,0 +1,9 @@
1
+name=PubSubClient
2
+version=2.7
3
+author=Nick O'Leary <nick.oleary@gmail.com>
4
+maintainer=Nick O'Leary <nick.oleary@gmail.com>
5
+sentence=A client library for MQTT messaging.
6
+paragraph=MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000.
7
+category=Communication
8
+url=http://pubsubclient.knolleary.net
9
+architectures=*

+ 653
- 0
Roomba/lib/PubSubClient_ID89/src/PubSubClient.cpp View File

@@ -0,0 +1,653 @@
1
+/*
2
+  PubSubClient.cpp - A simple client for MQTT.
3
+  Nick O'Leary
4
+  http://knolleary.net
5
+*/
6
+
7
+#include "PubSubClient.h"
8
+#include "Arduino.h"
9
+
10
+PubSubClient::PubSubClient() {
11
+    this->_state = MQTT_DISCONNECTED;
12
+    this->_client = NULL;
13
+    this->stream = NULL;
14
+    setCallback(NULL);
15
+}
16
+
17
+PubSubClient::PubSubClient(Client& client) {
18
+    this->_state = MQTT_DISCONNECTED;
19
+    setClient(client);
20
+    this->stream = NULL;
21
+}
22
+
23
+PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) {
24
+    this->_state = MQTT_DISCONNECTED;
25
+    setServer(addr, port);
26
+    setClient(client);
27
+    this->stream = NULL;
28
+}
29
+PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) {
30
+    this->_state = MQTT_DISCONNECTED;
31
+    setServer(addr,port);
32
+    setClient(client);
33
+    setStream(stream);
34
+}
35
+PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
36
+    this->_state = MQTT_DISCONNECTED;
37
+    setServer(addr, port);
38
+    setCallback(callback);
39
+    setClient(client);
40
+    this->stream = NULL;
41
+}
42
+PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
43
+    this->_state = MQTT_DISCONNECTED;
44
+    setServer(addr,port);
45
+    setCallback(callback);
46
+    setClient(client);
47
+    setStream(stream);
48
+}
49
+
50
+PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) {
51
+    this->_state = MQTT_DISCONNECTED;
52
+    setServer(ip, port);
53
+    setClient(client);
54
+    this->stream = NULL;
55
+}
56
+PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) {
57
+    this->_state = MQTT_DISCONNECTED;
58
+    setServer(ip,port);
59
+    setClient(client);
60
+    setStream(stream);
61
+}
62
+PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
63
+    this->_state = MQTT_DISCONNECTED;
64
+    setServer(ip, port);
65
+    setCallback(callback);
66
+    setClient(client);
67
+    this->stream = NULL;
68
+}
69
+PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
70
+    this->_state = MQTT_DISCONNECTED;
71
+    setServer(ip,port);
72
+    setCallback(callback);
73
+    setClient(client);
74
+    setStream(stream);
75
+}
76
+
77
+PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) {
78
+    this->_state = MQTT_DISCONNECTED;
79
+    setServer(domain,port);
80
+    setClient(client);
81
+    this->stream = NULL;
82
+}
83
+PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) {
84
+    this->_state = MQTT_DISCONNECTED;
85
+    setServer(domain,port);
86
+    setClient(client);
87
+    setStream(stream);
88
+}
89
+PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
90
+    this->_state = MQTT_DISCONNECTED;
91
+    setServer(domain,port);
92
+    setCallback(callback);
93
+    setClient(client);
94
+    this->stream = NULL;
95
+}
96
+PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
97
+    this->_state = MQTT_DISCONNECTED;
98
+    setServer(domain,port);
99
+    setCallback(callback);
100
+    setClient(client);
101
+    setStream(stream);
102
+}
103
+
104
+boolean PubSubClient::connect(const char *id) {
105
+    return connect(id,NULL,NULL,0,0,0,0,1);
106
+}
107
+
108
+boolean PubSubClient::connect(const char *id, const char *user, const char *pass) {
109
+    return connect(id,user,pass,0,0,0,0,1);
110
+}
111
+
112
+boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
113
+    return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage,1);
114
+}
115
+
116
+boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
117
+    return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1);
118
+}
119
+
120
+boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) {
121
+    if (!connected()) {
122
+        int result = 0;
123
+
124
+        if (domain != NULL) {
125
+            result = _client->connect(this->domain, this->port);
126
+        } else {
127
+            result = _client->connect(this->ip, this->port);
128
+        }
129
+        if (result == 1) {
130
+            nextMsgId = 1;
131
+            // Leave room in the buffer for header and variable length field
132
+            uint16_t length = MQTT_MAX_HEADER_SIZE;
133
+            unsigned int j;
134
+
135
+#if MQTT_VERSION == MQTT_VERSION_3_1
136
+            uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION};
137
+#define MQTT_HEADER_VERSION_LENGTH 9
138
+#elif MQTT_VERSION == MQTT_VERSION_3_1_1
139
+            uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION};
140
+#define MQTT_HEADER_VERSION_LENGTH 7
141
+#endif
142
+            for (j = 0;j<MQTT_HEADER_VERSION_LENGTH;j++) {
143
+                buffer[length++] = d[j];
144
+            }
145
+
146
+            uint8_t v;
147
+            if (willTopic) {
148
+                v = 0x04|(willQos<<3)|(willRetain<<5);
149
+            } else {
150
+                v = 0x00;
151
+            }
152
+            if (cleanSession) {
153
+                v = v|0x02;
154
+            }
155
+
156
+            if(user != NULL) {
157
+                v = v|0x80;
158
+
159
+                if(pass != NULL) {
160
+                    v = v|(0x80>>1);
161
+                }
162
+            }
163
+
164
+            buffer[length++] = v;
165
+
166
+            buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
167
+            buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
168
+
169
+            CHECK_STRING_LENGTH(length,id)
170
+            length = writeString(id,buffer,length);
171
+            if (willTopic) {
172
+                CHECK_STRING_LENGTH(length,willTopic)
173
+                length = writeString(willTopic,buffer,length);
174
+                CHECK_STRING_LENGTH(length,willMessage)
175
+                length = writeString(willMessage,buffer,length);
176
+            }
177
+
178
+            if(user != NULL) {
179
+                CHECK_STRING_LENGTH(length,user)
180
+                length = writeString(user,buffer,length);
181
+                if(pass != NULL) {
182
+                    CHECK_STRING_LENGTH(length,pass)
183
+                    length = writeString(pass,buffer,length);
184
+                }
185
+            }
186
+
187
+            write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE);
188
+
189
+            lastInActivity = lastOutActivity = millis();
190
+
191
+            while (!_client->available()) {
192
+                unsigned long t = millis();
193
+                if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
194
+                    _state = MQTT_CONNECTION_TIMEOUT;
195
+                    _client->stop();
196
+                    return false;
197
+                }
198
+            }
199
+            uint8_t llen;
200
+            uint16_t len = readPacket(&llen);
201
+
202
+            if (len == 4) {
203
+                if (buffer[3] == 0) {
204
+                    lastInActivity = millis();
205
+                    pingOutstanding = false;
206
+                    _state = MQTT_CONNECTED;
207
+                    return true;
208
+                } else {
209
+                    _state = buffer[3];
210
+                }
211
+            }
212
+            _client->stop();
213
+        } else {
214
+            _state = MQTT_CONNECT_FAILED;
215
+        }
216
+        return false;
217
+    }
218
+    return true;
219
+}
220
+
221
+// reads a byte into result
222
+boolean PubSubClient::readByte(uint8_t * result) {
223
+   uint32_t previousMillis = millis();
224
+   while(!_client->available()) {
225
+     yield();
226
+     uint32_t currentMillis = millis();
227
+     if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
228
+       return false;
229
+     }
230
+   }
231
+   *result = _client->read();
232
+   return true;
233
+}
234
+
235
+// reads a byte into result[*index] and increments index
236
+boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){
237
+  uint16_t current_index = *index;
238
+  uint8_t * write_address = &(result[current_index]);
239
+  if(readByte(write_address)){
240
+    *index = current_index + 1;
241
+    return true;
242
+  }
243
+  return false;
244
+}
245
+
246
+uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
247
+    uint16_t len = 0;
248
+    if(!readByte(buffer, &len)) return 0;
249
+    bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH;
250
+    uint32_t multiplier = 1;
251
+    uint16_t length = 0;
252
+    uint8_t digit = 0;
253
+    uint16_t skip = 0;
254
+    uint8_t start = 0;
255
+
256
+    do {
257
+        if (len == 5) {
258
+            // Invalid remaining length encoding - kill the connection
259
+            _state = MQTT_DISCONNECTED;
260
+            _client->stop();
261
+            return 0;
262
+        }
263
+        if(!readByte(&digit)) return 0;
264
+        buffer[len++] = digit;
265
+        length += (digit & 127) * multiplier;
266
+        multiplier *= 128;
267
+    } while ((digit & 128) != 0);
268
+    *lengthLength = len-1;
269
+
270
+    if (isPublish) {
271
+        // Read in topic length to calculate bytes to skip over for Stream writing
272
+        if(!readByte(buffer, &len)) return 0;
273
+        if(!readByte(buffer, &len)) return 0;
274
+        skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
275
+        start = 2;
276
+        if (buffer[0]&MQTTQOS1) {
277
+            // skip message id
278
+            skip += 2;
279
+        }
280
+    }
281
+
282
+    for (uint16_t i = start;i<length;i++) {
283
+        if(!readByte(&digit)) return 0;
284
+        if (this->stream) {
285
+            if (isPublish && len-*lengthLength-2>skip) {
286
+                this->stream->write(digit);
287
+            }
288
+        }
289
+        if (len < MQTT_MAX_PACKET_SIZE) {
290
+            buffer[len] = digit;
291
+        }
292
+        len++;
293
+    }
294
+
295
+    if (!this->stream && len > MQTT_MAX_PACKET_SIZE) {
296
+        len = 0; // This will cause the packet to be ignored.
297
+    }
298
+
299
+    return len;
300
+}
301
+
302
+boolean PubSubClient::loop() {
303
+    if (connected()) {
304
+        unsigned long t = millis();
305
+        if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) {
306
+            if (pingOutstanding) {
307
+                this->_state = MQTT_CONNECTION_TIMEOUT;
308
+                _client->stop();
309
+                return false;
310
+            } else {
311
+                buffer[0] = MQTTPINGREQ;
312
+                buffer[1] = 0;
313
+                _client->write(buffer,2);
314
+                lastOutActivity = t;
315
+                lastInActivity = t;
316
+                pingOutstanding = true;
317
+            }
318
+        }
319
+        if (_client->available()) {
320
+            uint8_t llen;
321
+            uint16_t len = readPacket(&llen);
322
+            uint16_t msgId = 0;
323
+            uint8_t *payload;
324
+            if (len > 0) {
325
+                lastInActivity = t;
326
+                uint8_t type = buffer[0]&0xF0;
327
+                if (type == MQTTPUBLISH) {
328
+                    if (callback) {
329
+                        uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; /* topic length in bytes */
330
+                        memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */
331
+                        buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */
332
+                        char *topic = (char*) buffer+llen+2;
333
+                        // msgId only present for QOS>0
334
+                        if ((buffer[0]&0x06) == MQTTQOS1) {
335
+                            msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1];
336
+                            payload = buffer+llen+3+tl+2;
337
+                            callback(topic,payload,len-llen-3-tl-2);
338
+
339
+                            buffer[0] = MQTTPUBACK;
340
+                            buffer[1] = 2;
341
+                            buffer[2] = (msgId >> 8);
342
+                            buffer[3] = (msgId & 0xFF);
343
+                            _client->write(buffer,4);
344
+                            lastOutActivity = t;
345
+
346
+                        } else {
347
+                            payload = buffer+llen+3+tl;
348
+                            callback(topic,payload,len-llen-3-tl);
349
+                        }
350
+                    }
351
+                } else if (type == MQTTPINGREQ) {
352
+                    buffer[0] = MQTTPINGRESP;
353
+                    buffer[1] = 0;
354
+                    _client->write(buffer,2);
355
+                } else if (type == MQTTPINGRESP) {
356
+                    pingOutstanding = false;
357
+                }
358
+            } else if (!connected()) {
359
+                // readPacket has closed the connection
360
+                return false;
361
+            }
362
+        }
363
+        return true;
364
+    }
365
+    return false;
366
+}
367
+
368
+boolean PubSubClient::publish(const char* topic, const char* payload) {
369
+    return publish(topic,(const uint8_t*)payload,strlen(payload),false);
370
+}
371
+
372
+boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) {
373
+    return publish(topic,(const uint8_t*)payload,strlen(payload),retained);
374
+}
375
+
376
+boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) {
377
+    return publish(topic, payload, plength, false);
378
+}
379
+
380
+boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
381
+    if (connected()) {
382
+        if (MQTT_MAX_PACKET_SIZE < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) {
383
+            // Too long
384
+            return false;
385
+        }
386
+        // Leave room in the buffer for header and variable length field
387
+        uint16_t length = MQTT_MAX_HEADER_SIZE;
388
+        length = writeString(topic,buffer,length);
389
+        uint16_t i;
390
+        for (i=0;i<plength;i++) {
391
+            buffer[length++] = payload[i];
392
+        }
393
+        uint8_t header = MQTTPUBLISH;
394
+        if (retained) {
395
+            header |= 1;
396
+        }
397
+        return write(header,buffer,length-MQTT_MAX_HEADER_SIZE);
398
+    }
399
+    return false;
400
+}
401
+
402
+boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) {
403
+    return publish_P(topic, (const uint8_t*)payload, strlen(payload), retained);
404
+}
405
+
406
+boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
407
+    uint8_t llen = 0;
408
+    uint8_t digit;
409
+    unsigned int rc = 0;
410
+    uint16_t tlen;
411
+    unsigned int pos = 0;
412
+    unsigned int i;
413
+    uint8_t header;
414
+    unsigned int len;
415
+
416
+    if (!connected()) {
417
+        return false;
418
+    }
419
+
420
+    tlen = strlen(topic);
421
+
422
+    header = MQTTPUBLISH;
423
+    if (retained) {
424
+        header |= 1;
425
+    }
426
+    buffer[pos++] = header;
427
+    len = plength + 2 + tlen;
428
+    do {
429
+        digit = len % 128;
430
+        len = len / 128;
431
+        if (len > 0) {
432
+            digit |= 0x80;
433
+        }
434
+        buffer[pos++] = digit;
435
+        llen++;
436
+    } while(len>0);
437
+
438
+    pos = writeString(topic,buffer,pos);
439
+
440
+    rc += _client->write(buffer,pos);
441
+
442
+    for (i=0;i<plength;i++) {
443
+        rc += _client->write((char)pgm_read_byte_near(payload + i));
444
+    }
445
+
446
+    lastOutActivity = millis();
447
+
448
+    return rc == tlen + 4 + plength;
449
+}
450
+
451
+boolean PubSubClient::beginPublish(const char* topic, unsigned int plength, boolean retained) {
452
+    if (connected()) {
453
+        // Send the header and variable length field
454
+        uint16_t length = MQTT_MAX_HEADER_SIZE;
455
+        length = writeString(topic,buffer,length);
456
+        uint16_t i;
457
+        uint8_t header = MQTTPUBLISH;
458
+        if (retained) {
459
+            header |= 1;
460
+        }
461
+        size_t hlen = buildHeader(header, buffer, plength+length-MQTT_MAX_HEADER_SIZE);
462
+        uint16_t rc = _client->write(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen));
463
+        lastOutActivity = millis();
464
+        return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen)));
465
+    }
466
+    return false;
467
+}
468
+
469
+int PubSubClient::endPublish() {
470
+ return 1;
471
+}
472
+
473
+size_t PubSubClient::write(uint8_t data) {
474
+    lastOutActivity = millis();
475
+    return _client->write(data);
476
+}
477
+
478
+size_t PubSubClient::write(const uint8_t *buffer, size_t size) {
479
+    lastOutActivity = millis();
480
+    return _client->write(buffer,size);
481
+}
482
+
483
+size_t PubSubClient::buildHeader(uint8_t header, uint8_t* buf, uint16_t length) {
484
+    uint8_t lenBuf[4];
485
+    uint8_t llen = 0;
486
+    uint8_t digit;
487
+    uint8_t pos = 0;
488
+    uint16_t len = length;
489
+    do {
490
+        digit = len % 128;
491
+        len = len / 128;
492
+        if (len > 0) {
493
+            digit |= 0x80;
494
+        }
495
+        lenBuf[pos++] = digit;
496
+        llen++;
497
+    } while(len>0);
498
+
499
+    buf[4-llen] = header;
500
+    for (int i=0;i<llen;i++) {
501
+        buf[MQTT_MAX_HEADER_SIZE-llen+i] = lenBuf[i];
502
+    }
503
+    return llen+1; // Full header size is variable length bit plus the 1-byte fixed header
504
+}
505
+
506
+boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
507
+    uint16_t rc;
508
+    uint8_t hlen = buildHeader(header, buf, length);
509
+
510
+#ifdef MQTT_MAX_TRANSFER_SIZE
511
+    uint8_t* writeBuf = buf+(MQTT_MAX_HEADER_SIZE-hlen);
512
+    uint16_t bytesRemaining = length+hlen;  //Match the length type
513
+    uint8_t bytesToWrite;
514
+    boolean result = true;
515
+    while((bytesRemaining > 0) && result) {
516
+        bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining;
517
+        rc = _client->write(writeBuf,bytesToWrite);
518
+        result = (rc == bytesToWrite);
519
+        bytesRemaining -= rc;
520
+        writeBuf += rc;
521
+    }
522
+    return result;
523
+#else
524
+    rc = _client->write(buf+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen);
525
+    lastOutActivity = millis();
526
+    return (rc == hlen+length);
527
+#endif
528
+}
529
+
530
+boolean PubSubClient::subscribe(const char* topic) {
531
+    return subscribe(topic, 0);
532
+}
533
+
534
+boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
535
+    if (qos > 1) {
536
+        return false;
537
+    }
538
+    if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
539
+        // Too long
540
+        return false;
541
+    }
542
+    if (connected()) {
543
+        // Leave room in the buffer for header and variable length field
544
+        uint16_t length = MQTT_MAX_HEADER_SIZE;
545
+        nextMsgId++;
546
+        if (nextMsgId == 0) {
547
+            nextMsgId = 1;
548
+        }
549
+        buffer[length++] = (nextMsgId >> 8);
550
+        buffer[length++] = (nextMsgId & 0xFF);
551
+        length = writeString((char*)topic, buffer,length);
552
+        buffer[length++] = qos;
553
+        return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
554
+    }
555
+    return false;
556
+}
557
+
558
+boolean PubSubClient::unsubscribe(const char* topic) {
559
+    if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
560
+        // Too long
561
+        return false;
562
+    }
563
+    if (connected()) {
564
+        uint16_t length = MQTT_MAX_HEADER_SIZE;
565
+        nextMsgId++;
566
+        if (nextMsgId == 0) {
567
+            nextMsgId = 1;
568
+        }
569
+        buffer[length++] = (nextMsgId >> 8);
570
+        buffer[length++] = (nextMsgId & 0xFF);
571
+        length = writeString(topic, buffer,length);
572
+        return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-MQTT_MAX_HEADER_SIZE);
573
+    }
574
+    return false;
575
+}
576
+
577
+void PubSubClient::disconnect() {
578
+    buffer[0] = MQTTDISCONNECT;
579
+    buffer[1] = 0;
580
+    _client->write(buffer,2);
581
+    _state = MQTT_DISCONNECTED;
582
+    _client->flush();
583
+    _client->stop();
584
+    lastInActivity = lastOutActivity = millis();
585
+}
586
+
587
+uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) {
588
+    const char* idp = string;
589
+    uint16_t i = 0;
590
+    pos += 2;
591
+    while (*idp) {
592
+        buf[pos++] = *idp++;
593
+        i++;
594
+    }
595
+    buf[pos-i-2] = (i >> 8);
596
+    buf[pos-i-1] = (i & 0xFF);
597
+    return pos;
598
+}
599
+
600
+
601
+boolean PubSubClient::connected() {
602
+    boolean rc;
603
+    if (_client == NULL ) {
604
+        rc = false;
605
+    } else {
606
+        rc = (int)_client->connected();
607
+        if (!rc) {
608
+            if (this->_state == MQTT_CONNECTED) {
609
+                this->_state = MQTT_CONNECTION_LOST;
610
+                _client->flush();
611
+                _client->stop();
612
+            }
613
+        }
614
+    }
615
+    return rc;
616
+}
617
+
618
+PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) {
619
+    IPAddress addr(ip[0],ip[1],ip[2],ip[3]);
620
+    return setServer(addr,port);
621
+}
622
+
623
+PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) {
624
+    this->ip = ip;
625
+    this->port = port;
626
+    this->domain = NULL;
627
+    return *this;
628
+}
629
+
630
+PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) {
631
+    this->domain = domain;
632
+    this->port = port;
633
+    return *this;
634
+}
635
+
636
+PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) {
637
+    this->callback = callback;
638
+    return *this;
639
+}
640
+
641
+PubSubClient& PubSubClient::setClient(Client& client){
642
+    this->_client = &client;
643
+    return *this;
644
+}
645
+
646
+PubSubClient& PubSubClient::setStream(Stream& stream){
647
+    this->stream = &stream;
648
+    return *this;
649
+}
650
+
651
+int PubSubClient::state() {
652
+    return this->_state;
653
+}

+ 173
- 0
Roomba/lib/PubSubClient_ID89/src/PubSubClient.h View File

@@ -0,0 +1,173 @@
1
+/*
2
+ PubSubClient.h - A simple client for MQTT.
3
+  Nick O'Leary
4
+  http://knolleary.net
5
+*/
6
+
7
+#ifndef PubSubClient_h
8
+#define PubSubClient_h
9
+
10
+#include <Arduino.h>
11
+#include "IPAddress.h"
12
+#include "Client.h"
13
+#include "Stream.h"
14
+
15
+#define MQTT_VERSION_3_1      3
16
+#define MQTT_VERSION_3_1_1    4
17
+
18
+// MQTT_VERSION : Pick the version
19
+//#define MQTT_VERSION MQTT_VERSION_3_1
20
+#ifndef MQTT_VERSION
21
+#define MQTT_VERSION MQTT_VERSION_3_1_1
22
+#endif
23
+
24
+// MQTT_MAX_PACKET_SIZE : Maximum packet size
25
+#ifndef MQTT_MAX_PACKET_SIZE
26
+#define MQTT_MAX_PACKET_SIZE 128
27
+#endif
28
+
29
+// MQTT_KEEPALIVE : keepAlive interval in Seconds
30
+#ifndef MQTT_KEEPALIVE
31
+#define MQTT_KEEPALIVE 15
32
+#endif
33
+
34
+// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
35
+#ifndef MQTT_SOCKET_TIMEOUT
36
+#define MQTT_SOCKET_TIMEOUT 15
37
+#endif
38
+
39
+// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client
40
+//  in each write call. Needed for the Arduino Wifi Shield. Leave undefined to
41
+//  pass the entire MQTT packet in each write call.
42
+//#define MQTT_MAX_TRANSFER_SIZE 80
43
+
44
+// Possible values for client.state()
45
+#define MQTT_CONNECTION_TIMEOUT     -4
46
+#define MQTT_CONNECTION_LOST        -3
47
+#define MQTT_CONNECT_FAILED         -2
48
+#define MQTT_DISCONNECTED           -1
49
+#define MQTT_CONNECTED               0
50
+#define MQTT_CONNECT_BAD_PROTOCOL    1
51
+#define MQTT_CONNECT_BAD_CLIENT_ID   2
52
+#define MQTT_CONNECT_UNAVAILABLE     3
53
+#define MQTT_CONNECT_BAD_CREDENTIALS 4
54
+#define MQTT_CONNECT_UNAUTHORIZED    5
55
+
56
+#define MQTTCONNECT     1 << 4  // Client request to connect to Server
57
+#define MQTTCONNACK     2 << 4  // Connect Acknowledgment
58
+#define MQTTPUBLISH     3 << 4  // Publish message
59
+#define MQTTPUBACK      4 << 4  // Publish Acknowledgment
60
+#define MQTTPUBREC      5 << 4  // Publish Received (assured delivery part 1)
61
+#define MQTTPUBREL      6 << 4  // Publish Release (assured delivery part 2)
62
+#define MQTTPUBCOMP     7 << 4  // Publish Complete (assured delivery part 3)
63
+#define MQTTSUBSCRIBE   8 << 4  // Client Subscribe request
64
+#define MQTTSUBACK      9 << 4  // Subscribe Acknowledgment
65
+#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request
66
+#define MQTTUNSUBACK    11 << 4 // Unsubscribe Acknowledgment
67
+#define MQTTPINGREQ     12 << 4 // PING Request
68
+#define MQTTPINGRESP    13 << 4 // PING Response
69
+#define MQTTDISCONNECT  14 << 4 // Client is Disconnecting
70
+#define MQTTReserved    15 << 4 // Reserved
71
+
72
+#define MQTTQOS0        (0 << 1)
73
+#define MQTTQOS1        (1 << 1)
74
+#define MQTTQOS2        (2 << 1)
75
+
76
+// Maximum size of fixed header and variable length size header
77
+#define MQTT_MAX_HEADER_SIZE 5
78
+
79
+#if defined(ESP8266) || defined(ESP32)
80
+#include <functional>
81
+#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
82
+#else
83
+#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
84
+#endif
85
+
86
+#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
87
+
88
+class PubSubClient : public Print {
89
+private:
90
+   Client* _client;
91
+   uint8_t buffer[MQTT_MAX_PACKET_SIZE];
92
+   uint16_t nextMsgId;
93
+   unsigned long lastOutActivity;
94
+   unsigned long lastInActivity;
95
+   bool pingOutstanding;
96
+   MQTT_CALLBACK_SIGNATURE;
97
+   uint16_t readPacket(uint8_t*);
98
+   boolean readByte(uint8_t * result);
99
+   boolean readByte(uint8_t * result, uint16_t * index);
100
+   boolean write(uint8_t header, uint8_t* buf, uint16_t length);
101
+   uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
102
+   // Build up the header ready to send
103
+   // Returns the size of the header
104
+   // Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start
105
+   //       (MQTT_MAX_HEADER_SIZE - <returned size>) bytes into the buffer
106
+   size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
107
+   IPAddress ip;
108
+   const char* domain;
109
+   uint16_t port;
110
+   Stream* stream;
111
+   int _state;
112
+public:
113
+   PubSubClient();
114
+   PubSubClient(Client& client);
115
+   PubSubClient(IPAddress, uint16_t, Client& client);
116
+   PubSubClient(IPAddress, uint16_t, Client& client, Stream&);
117
+   PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
118
+   PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
119
+   PubSubClient(uint8_t *, uint16_t, Client& client);
120
+   PubSubClient(uint8_t *, uint16_t, Client& client, Stream&);
121
+   PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
122
+   PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
123
+   PubSubClient(const char*, uint16_t, Client& client);
124
+   PubSubClient(const char*, uint16_t, Client& client, Stream&);
125
+   PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
126
+   PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
127
+
128
+   PubSubClient& setServer(IPAddress ip, uint16_t port);
129
+   PubSubClient& setServer(uint8_t * ip, uint16_t port);
130
+   PubSubClient& setServer(const char * domain, uint16_t port);
131
+   PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE);
132
+   PubSubClient& setClient(Client& client);
133
+   PubSubClient& setStream(Stream& stream);
134
+
135
+   boolean connect(const char* id);
136
+   boolean connect(const char* id, const char* user, const char* pass);
137
+   boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
138
+   boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
139
+   boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession);
140
+   void disconnect();
141
+   boolean publish(const char* topic, const char* payload);
142
+   boolean publish(const char* topic, const char* payload, boolean retained);
143
+   boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);
144
+   boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
145
+   boolean publish_P(const char* topic, const char* payload, boolean retained);
146
+   boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
147
+   // Start to publish a message.
148
+   // This API:
149
+   //   beginPublish(...)
150
+   //   one or more calls to write(...)
151
+   //   endPublish()
152
+   // Allows for arbitrarily large payloads to be sent without them having to be copied into
153
+   // a new buffer and held in memory at one time
154
+   // Returns 1 if the message was started successfully, 0 if there was an error
155
+   boolean beginPublish(const char* topic, unsigned int plength, boolean retained);
156
+   // Finish off this publish message (started with beginPublish)
157
+   // Returns 1 if the packet was sent successfully, 0 if there was an error
158
+   int endPublish();
159
+   // Write a single byte of payload (only to be used with beginPublish/endPublish)
160
+   virtual size_t write(uint8_t);
161
+   // Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish)
162
+   // Returns the number of bytes written
163
+   virtual size_t write(const uint8_t *buffer, size_t size);
164
+   boolean subscribe(const char* topic);
165
+   boolean subscribe(const char* topic, uint8_t qos);
166
+   boolean unsubscribe(const char* topic);
167
+   boolean loop();
168
+   boolean connected();
169
+   int state();
170
+};
171
+
172
+
173
+#endif

+ 0
- 0
Roomba/lib/SimpleTimer_ID419/.gitignore View File


+ 27
- 0
Roomba/lib/SimpleTimer_ID419/.library.json View File

@@ -0,0 +1,27 @@
1
+{
2
+    "name": "SimpleTimer", 
3
+    "repository": {
4
+        "url": "https://github.com/jfturcot/SimpleTimer.git", 
5
+        "type": "git"
6
+    }, 
7
+    "platforms": [
8
+        "atmelavr"
9
+    ], 
10
+    "frameworks": [
11
+        "arduino"
12
+    ], 
13
+    "version": "b30890b8f7", 
14
+    "authors": [
15
+        {
16
+            "maintainer": false, 
17
+            "name": "Jean-Francois Turcot", 
18
+            "url": "https://github.com/jfturcot", 
19
+            "email": "jf.turcot@gmail.com"
20
+        }
21
+    ], 
22
+    "keywords": [
23
+        "timer"
24
+    ], 
25
+    "id": 419, 
26
+    "description": "SimpleTimer Library for Arduino"
27
+}

+ 2
- 0
Roomba/lib/SimpleTimer_ID419/README View File

@@ -0,0 +1,2 @@
1
+Visit this page for more information:
2
+http://playground.arduino.cc/Code/SimpleTimer

+ 241
- 0
Roomba/lib/SimpleTimer_ID419/SimpleTimer.cpp View File

@@ -0,0 +1,241 @@
1
+/*
2
+ * SimpleTimer.cpp
3
+ *
4
+ * SimpleTimer - A timer library for Arduino.
5
+ * Author: mromani@ottotecnica.com
6
+ * Copyright (c) 2010 OTTOTECNICA Italy
7
+ *
8
+ * This library is free software; you can redistribute it
9
+ * and/or modify it under the terms of the GNU Lesser
10
+ * General Public License as published by the Free Software
11
+ * Foundation; either version 2.1 of the License, or (at
12
+ * your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will
15
+ * be useful, but WITHOUT ANY WARRANTY; without even the
16
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
17
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public
18
+ * License for more details.
19
+ *
20
+ * You should have received a copy of the GNU Lesser
21
+ * General Public License along with this library; if not,
22
+ * write to the Free Software Foundation, Inc.,
23
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+ */
25
+
26
+
27
+#include "SimpleTimer.h"
28
+
29
+
30
+// Select time function:
31
+//static inline unsigned long elapsed() { return micros(); }
32
+static inline unsigned long elapsed() { return millis(); }
33
+
34
+
35
+SimpleTimer::SimpleTimer() {
36
+    unsigned long current_millis = elapsed();
37
+
38
+    for (int i = 0; i < MAX_TIMERS; i++) {
39
+        enabled[i] = false;
40
+        callbacks[i] = 0;                   // if the callback pointer is zero, the slot is free, i.e. doesn't "contain" any timer
41
+        prev_millis[i] = current_millis;
42
+        numRuns[i] = 0;
43
+    }
44
+
45
+    numTimers = 0;
46
+}
47
+
48
+
49
+void SimpleTimer::run() {
50
+    int i;
51
+    unsigned long current_millis;
52
+
53
+    // get current time
54
+    current_millis = elapsed();
55
+
56
+    for (i = 0; i < MAX_TIMERS; i++) {
57
+
58
+        toBeCalled[i] = DEFCALL_DONTRUN;
59
+
60
+        // no callback == no timer, i.e. jump over empty slots
61
+        if (callbacks[i]) {
62
+
63
+            // is it time to process this timer ?
64
+            // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592
65
+
66
+            if (current_millis - prev_millis[i] >= delays[i]) {
67
+
68
+                // update time
69
+                //prev_millis[i] = current_millis;
70
+                prev_millis[i] += delays[i];
71
+
72
+                // check if the timer callback has to be executed
73
+                if (enabled[i]) {
74
+
75
+                    // "run forever" timers must always be executed
76
+                    if (maxNumRuns[i] == RUN_FOREVER) {
77
+                        toBeCalled[i] = DEFCALL_RUNONLY;
78
+                    }
79
+                    // other timers get executed the specified number of times
80
+                    else if (numRuns[i] < maxNumRuns[i]) {
81
+                        toBeCalled[i] = DEFCALL_RUNONLY;
82
+                        numRuns[i]++;
83
+
84
+                        // after the last run, delete the timer
85
+                        if (numRuns[i] >= maxNumRuns[i]) {
86
+                            toBeCalled[i] = DEFCALL_RUNANDDEL;
87
+                        }
88
+                    }
89
+                }
90
+            }
91
+        }
92
+    }
93
+
94
+    for (i = 0; i < MAX_TIMERS; i++) {
95
+        switch(toBeCalled[i]) {
96
+            case DEFCALL_DONTRUN:
97
+                break;
98
+
99
+            case DEFCALL_RUNONLY:
100
+                (*callbacks[i])();
101
+                break;
102
+
103
+            case DEFCALL_RUNANDDEL:
104
+                (*callbacks[i])();
105
+                deleteTimer(i);
106
+                break;
107
+        }
108
+    }
109
+}
110
+
111
+
112
+// find the first available slot
113
+// return -1 if none found
114
+int SimpleTimer::findFirstFreeSlot() {
115
+    int i;
116
+
117
+    // all slots are used
118
+    if (numTimers >= MAX_TIMERS) {
119
+        return -1;
120
+    }
121
+
122
+    // return the first slot with no callback (i.e. free)
123
+    for (i = 0; i < MAX_TIMERS; i++) {
124
+        if (callbacks[i] == 0) {
125
+            return i;
126
+        }
127
+    }
128
+
129
+    // no free slots found
130
+    return -1;
131
+}
132
+
133
+
134
+int SimpleTimer::setTimer(long d, timer_callback f, int n) {
135
+    int freeTimer;
136
+
137
+    freeTimer = findFirstFreeSlot();
138
+    if (freeTimer < 0) {
139
+        return -1;
140
+    }
141
+
142
+    if (f == NULL) {
143
+        return -1;
144
+    }
145
+
146
+    delays[freeTimer] = d;
147
+    callbacks[freeTimer] = f;
148
+    maxNumRuns[freeTimer] = n;
149
+    enabled[freeTimer] = true;
150
+    prev_millis[freeTimer] = elapsed();
151
+
152
+    numTimers++;
153
+
154
+    return freeTimer;
155
+}
156
+
157
+
158
+int SimpleTimer::setInterval(long d, timer_callback f) {
159
+    return setTimer(d, f, RUN_FOREVER);
160
+}
161
+
162
+
163
+int SimpleTimer::setTimeout(long d, timer_callback f) {
164
+    return setTimer(d, f, RUN_ONCE);
165
+}
166
+
167
+
168
+void SimpleTimer::deleteTimer(int timerId) {
169
+    if (timerId >= MAX_TIMERS) {
170
+        return;
171
+    }
172
+
173
+    // nothing to delete if no timers are in use
174
+    if (numTimers == 0) {
175
+        return;
176
+    }
177
+
178
+    // don't decrease the number of timers if the
179
+    // specified slot is already empty
180
+    if (callbacks[timerId] != NULL) {
181
+        callbacks[timerId] = 0;
182
+        enabled[timerId] = false;
183
+        toBeCalled[timerId] = DEFCALL_DONTRUN;
184
+        delays[timerId] = 0;
185
+        numRuns[timerId] = 0;
186
+
187
+        // update number of timers
188
+        numTimers--;
189
+    }
190
+}
191
+
192
+
193
+// function contributed by code@rowansimms.com
194
+void SimpleTimer::restartTimer(int numTimer) {
195
+    if (numTimer >= MAX_TIMERS) {
196
+        return;
197
+    }
198
+
199
+    prev_millis[numTimer] = elapsed();
200
+}
201
+
202
+
203
+boolean SimpleTimer::isEnabled(int numTimer) {
204
+    if (numTimer >= MAX_TIMERS) {
205
+        return false;
206
+    }
207
+
208
+    return enabled[numTimer];
209
+}
210
+
211
+
212
+void SimpleTimer::enable(int numTimer) {
213
+    if (numTimer >= MAX_TIMERS) {
214
+        return;
215
+    }
216
+
217
+    enabled[numTimer] = true;
218
+}
219
+
220
+
221
+void SimpleTimer::disable(int numTimer) {
222
+    if (numTimer >= MAX_TIMERS) {
223
+        return;
224
+    }
225
+
226
+    enabled[numTimer] = false;
227
+}
228
+
229
+
230
+void SimpleTimer::toggle(int numTimer) {
231
+    if (numTimer >= MAX_TIMERS) {
232
+        return;
233
+    }
234
+
235
+    enabled[numTimer] = !enabled[numTimer];
236
+}
237
+
238
+
239
+int SimpleTimer::getNumTimers() {
240
+    return numTimers;
241
+}

+ 124
- 0
Roomba/lib/SimpleTimer_ID419/SimpleTimer.h View File

@@ -0,0 +1,124 @@
1
+/*
2
+ * SimpleTimer.h
3
+ *
4
+ * SimpleTimer - A timer library for Arduino.
5
+ * Author: mromani@ottotecnica.com
6
+ * Copyright (c) 2010 OTTOTECNICA Italy
7
+ *
8
+ * This library is free software; you can redistribute it
9
+ * and/or modify it under the terms of the GNU Lesser
10
+ * General Public License as published by the Free Software
11
+ * Foundation; either version 2.1 of the License, or (at
12
+ * your option) any later version.
13
+ *
14
+ * This library is distributed in the hope that it will
15
+ * be useful, but WITHOUT ANY WARRANTY; without even the
16
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A
17
+ * PARTICULAR PURPOSE.  See the GNU Lesser General Public
18
+ * License for more details.
19
+ *
20
+ * You should have received a copy of the GNU Lesser
21
+ * General Public License along with this library; if not,
22
+ * write to the Free Software Foundation, Inc.,
23
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
+ *
25
+ */
26
+
27
+
28
+#ifndef SIMPLETIMER_H
29
+#define SIMPLETIMER_H
30
+
31
+#if defined(ARDUINO) && ARDUINO >= 100
32
+#include <Arduino.h>
33
+#else
34
+#include <WProgram.h>
35
+#endif
36
+
37
+typedef void (*timer_callback)(void);
38
+
39
+class SimpleTimer {
40
+
41
+public:
42
+    // maximum number of timers
43
+    const static int MAX_TIMERS = 10;
44
+
45
+    // setTimer() constants
46
+    const static int RUN_FOREVER = 0;
47
+    const static int RUN_ONCE = 1;
48
+
49
+    // constructor
50
+    SimpleTimer();
51
+
52
+    // this function must be called inside loop()
53
+    void run();
54
+
55
+    // call function f every d milliseconds
56
+    int setInterval(long d, timer_callback f);
57
+
58
+    // call function f once after d milliseconds
59
+    int setTimeout(long d, timer_callback f);
60
+
61
+    // call function f every d milliseconds for n times
62
+    int setTimer(long d, timer_callback f, int n);
63
+
64
+    // destroy the specified timer
65
+    void deleteTimer(int numTimer);
66
+
67
+    // restart the specified timer
68
+    void restartTimer(int numTimer);
69
+
70
+    // returns true if the specified timer is enabled
71
+    boolean isEnabled(int numTimer);
72
+
73
+    // enables the specified timer
74
+    void enable(int numTimer);
75
+
76
+    // disables the specified timer
77
+    void disable(int numTimer);
78
+
79
+    // enables the specified timer if it's currently disabled,
80
+    // and vice-versa
81
+    void toggle(int numTimer);
82
+
83
+    // returns the number of used timers
84
+    int getNumTimers();
85
+
86
+    // returns the number of available timers
87
+    int getNumAvailableTimers() { return MAX_TIMERS - numTimers; };
88
+
89
+private:
90
+    // deferred call constants
91
+    const static int DEFCALL_DONTRUN = 0;       // don't call the callback function
92
+    const static int DEFCALL_RUNONLY = 1;       // call the callback function but don't delete the timer
93
+    const static int DEFCALL_RUNANDDEL = 2;      // call the callback function and delete the timer
94
+
95
+    // find the first available slot
96
+    int findFirstFreeSlot();
97
+
98
+    // value returned by the millis() function
99
+    // in the previous run() call
100
+    unsigned long prev_millis[MAX_TIMERS];
101
+
102
+    // pointers to the callback functions
103
+    timer_callback callbacks[MAX_TIMERS];
104
+
105
+    // delay values
106
+    long delays[MAX_TIMERS];
107
+
108
+    // number of runs to be executed for each timer
109
+    int maxNumRuns[MAX_TIMERS];
110
+
111
+    // number of executed runs for each timer
112
+    int numRuns[MAX_TIMERS];
113
+
114
+    // which timers are enabled
115
+    boolean enabled[MAX_TIMERS];
116
+
117
+    // deferred function call (sort of) - N.B.: this array is only used in run()
118
+    int toBeCalled[MAX_TIMERS];
119
+
120
+    // actual number of timers in use
121
+    int numTimers;
122
+};
123
+
124
+#endif

+ 12
- 0
Roomba/lib/SimpleTimer_ID419/library.json View File

@@ -0,0 +1,12 @@
1
+{
2
+  "name": "SimpleTimer",
3
+  "keywords": "timer",
4
+  "description": "SimpleTimer Library for Arduino",
5
+  "repository":
6
+  {
7
+     "type": "git",
8
+     "url": "https://github.com/jfturcot/SimpleTimer.git"
9
+  },
10
+  "frameworks": "arduino",
11
+  "platforms": "atmelavr"
12
+ }

+ 20
- 0
Roomba/platformio.ini View File

@@ -0,0 +1,20 @@
1
+; PlatformIO Project Configuration File
2
+;
3
+;   Build options: build flags, source filter
4
+;   Upload options: custom upload port, speed and extra flags
5
+;   Library options: dependencies, extra library storages
6
+;   Advanced options: extra scripting
7
+;
8
+; Please visit documentation for the other options and examples
9
+; http://docs.platformio.org/page/projectconf.html
10
+
11
+[env:esp01_1m]
12
+;board_build.f_cpu = 160000000L
13
+;platform = espressif8266
14
+platform = https://github.com/platformio/platform-espressif8266.git#feature/stage
15
+board = esp01_1m
16
+framework = arduino
17
+build_flags =
18
+  -Wl,-Teagle.flash.1m.ld
19
+  -D PIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH
20
+  -DNDEBUG

+ 391
- 0
Roomba/src/Roomba.ino View File

@@ -0,0 +1,391 @@
1
+#include <PubSubClient.h>
2
+#include <ESP8266WiFi.h>
3
+#include <ESP8266WebServer.h>
4
+//#include <ESP8266HTTPClient.h>
5
+#include <ESP8266httpUpdate.h>
6
+#include <ESP8266HTTPUpdateServer.h>
7
+#include <SimpleTimer.h>
8
+
9
+// USER CONFIGURED SECTION START //
10
+const char* ssid = "YOURSSID";
11
+const char* password = "YOURPASSWORD";
12
+const char* mqtt_server = "MQTTIP";
13
+const int mqtt_port = 1883;
14
+const char *mqtt_user = NULL;
15
+const char *mqtt_pass = NULL;
16
+
17
+WiFiClient espClient;
18
+PubSubClient client(espClient);
19
+SimpleTimer timer;
20
+
21
+#define noSleepPin 0
22
+#define ROOMBA_READ_TIMEOUT 200
23
+#define STATE_UNKNOWN 0
24
+#define STATE_CLEANING 1
25
+#define STATE_RETURNING 2
26
+#define STATE_DOCKED 3
27
+
28
+ESP8266WebServer httpServer(80);
29
+ESP8266HTTPUpdateServer httpUpdater;
30
+
31
+// Variables
32
+bool boot = true;
33
+uint16_t battery_capacity = 0; //mAh
34
+uint16_t battery_charge = 0; //mAh
35
+int16_t battery_current = 0;
36
+uint8_t battery_percent = 0;
37
+uint8_t battery_temp = 0;
38
+uint16_t battery_voltage = 0;
39
+uint8_t chargeState = 0;
40
+uint8_t num_restarts = 0;
41
+uint8_t current_state = 0;
42
+String last_status;
43
+String update_status;
44
+String currentStatus;
45
+
46
+void setup() {
47
+	setup_wifi();
48
+	checkForUpdate();
49
+
50
+	// Reset the Roomba.
51
+	Serial.begin(115200);
52
+	pinMode(noSleepPin, OUTPUT);
53
+	digitalWrite(noSleepPin, HIGH);
54
+	resetRoomba();
55
+
56
+	httpServer.on("/", handle_root);
57
+	httpServer.on("/reboot", reboot);
58
+	httpUpdater.setup(&httpServer);
59
+	httpServer.begin();
60
+
61
+	client.setServer(mqtt_server, mqtt_port);
62
+	client.setCallback(callback);
63
+
64
+	timer.setInterval(10000, getSensors);
65
+	timer.setInterval(59000, StayAwake);
66
+	timer.setInterval(4 * 60 * 60 * 1000, checkForUpdate);	// Check for update every 4 hours.
67
+}
68
+
69
+void loop() {
70
+	httpServer.handleClient();
71
+	if (!client.connected()) 
72
+	{
73
+		reconnect();
74
+	}
75
+	client.loop();
76
+	timer.run();
77
+	delay(50);
78
+}
79
+
80
+void checkForUpdate() {
81
+	update_status = F("Checking for update...\n");
82
+
83
+	BearSSL::WiFiClientSecure UpdateClient;
84
+	UpdateClient.setInsecure();
85
+	t_httpUpdate_return result = ESPhttpUpdate.update(UpdateClient, F("https://10.1.1.93/arduino/update/"));
86
+
87
+	//WiFiClient UpdateClient;
88
+	//t_httpUpdate_return result = ESPhttpUpdate.update(UpdateClient, F("http://10.1.1.93/arduino/update/"));
89
+
90
+	update_status += F("Returned: ");
91
+	switch(result) {
92
+		case HTTP_UPDATE_FAILED:
93
+			update_status += F("Update failed:\nLastError: ");
94
+			update_status += ESPhttpUpdate.getLastError();
95
+			update_status += F("\nError: ");
96
+			update_status += ESPhttpUpdate.getLastErrorString().c_str();
97
+			update_status += F("\n");
98
+			break;
99
+		case HTTP_UPDATE_NO_UPDATES:
100
+			update_status += F("No Update Available.\n");
101
+			break;
102
+		case HTTP_UPDATE_OK:
103
+			update_status += F("Updated OK.\n");
104
+			break;
105
+	}
106
+}
107
+
108
+//Functions
109
+void setup_wifi() {
110
+	WiFi.mode(WIFI_STA);
111
+	WiFi.begin(ssid, password);
112
+	while (WiFi.status() != WL_CONNECTED) {
113
+		delay(100);
114
+	}
115
+}
116
+
117
+void reconnect() {
118
+	if (client.connect(WiFi.macAddress().c_str(), mqtt_user, mqtt_pass, "roomba/status", 0, 0, "Not responding")) {
119
+		// Once connected, publish an announcement...
120
+		if(boot == false) {
121
+			client.publish("checkIn/roomba", "Reconnected");
122
+		}
123
+		if(boot == true) {
124
+			client.publish("checkIn/roomba", "Rebooted");
125
+			boot = false;
126
+		}
127
+		// ... and resubscribe
128
+		client.subscribe("roomba/commands");
129
+    }
130
+}
131
+
132
+void callback(char* topic, byte* payload, unsigned int length) {
133
+	String newTopic = topic;
134
+	payload[length] = '\0';
135
+	String newPayload = String((char *)payload);
136
+
137
+	if (newTopic == "roomba/commands") {
138
+		// Reset num_restarts so our command has a chance of working after error
139
+		num_restarts = 0;
140
+
141
+		if (newPayload == "start") {
142
+			startCleaning();
143
+		}
144
+		if (newPayload == "stop") {
145
+			stopCleaning();
146
+		}
147
+	}
148
+}
149
+
150
+void getSensors() {
151
+	char tmp[5];
152
+	char buffer[10];
153
+
154
+	last_status = "getSensors - Running\n";
155
+
156
+	// Clear any read buffer remaining.
157
+	int i = 0;
158
+	while ( Serial.available() > 0 ) {
159
+		Serial.read();
160
+		i++;
161
+		delay(5);
162
+	}
163
+	if ( i > 0 ) {
164
+		last_status = "Dumped ";
165
+		last_status += i;
166
+		last_status += " bytes.\n";
167
+	}
168
+
169
+	// Ask for sensor group 3.
170
+	// 21 (1 byte reply) - charge state
171
+	// 22 (2 byte reply) - battery voltage
172
+	// 23 (2 byte reply) - battery_current
173
+	// 24 (1 byte reply) - battery_temp
174
+	// 25 (2 byte reply) - battery charge
175
+	// 26 (2 byte reply) - battery capacity
176
+	byte command[] = { 128, 149, 1, 3 };
177
+	SendCommandList( command, 4 );
178
+
179
+	// We should get 10 bytes back.
180
+	i = 0;
181
+	last_status += "RX: ";
182
+	while ( Serial.available() > 0) {
183
+		buffer[i] = Serial.read();
184
+		last_status += String(buffer[i], DEC);
185
+		last_status += " ";
186
+		i++;
187
+		delay(3);
188
+	}
189
+	last_status += "\n";
190
+
191
+	// Handle if the Roomba stops responding.
192
+	if ( i == 0 ) {
193
+		last_status += "ERROR: No response\n";
194
+		client.publish("roomba/status", "Not Responding");
195
+		client.publish("roomba/currentStatus", "Not Responding");
196
+		return;
197
+	}
198
+
199
+	// Handle an incomplete packet (too much or too little data)
200
+	if ( i != 10 ) {
201
+		last_status += "ERROR: Incomplete packet recieved ";
202
+		last_status += i;
203
+		last_status += " bytes.\n";
204
+		return;
205
+	}
206
+
207
+	// Parse the buffer...
208
+	uint8_t new_chargeState = buffer[0];
209
+	battery_voltage = (uint16_t)word(buffer[1], buffer[2]);
210
+	battery_current = (int16_t)word(buffer[3], buffer[4]);
211
+	battery_temp = buffer[5];
212
+	battery_charge = (uint16_t)word(buffer[6], buffer[7]);
213
+	battery_capacity = (uint16_t)word(buffer[8], buffer[9]);
214
+	
215
+	// Sanity check some data...
216
+	if ( new_chargeState > 6 ) { return; }			// Values should be 0-6
217
+	if ( battery_capacity == 0 ) { return; }		// We should never get this - but we don't want to divide by zero!
218
+	if ( battery_capacity > 6000 ) { return; }		// Usually around 2050 or so.
219
+	if ( battery_charge > 6000 ) { return; }		// Can't be greater than battery_capacity
220
+	if ( battery_voltage > 18000 ) { return; }		// Should be about 17v on charge, down to ~13.1v when flat.
221
+
222
+	uint8_t new_battery_percent = 100 * battery_charge / battery_capacity;
223
+	if ( battery_percent > 100 ) { return; }
224
+	if ( battery_percent != new_battery_percent ) {
225
+		battery_percent = new_battery_percent;
226
+		itoa(battery_percent, tmp, 10);
227
+		client.publish("roomba/battery", tmp, true);
228
+	}
229
+
230
+	if ( chargeState != new_chargeState ) {
231
+		// If we've gone from non-docked to docked, reflect that state.
232
+		if ( chargeState == 0 and (new_chargeState >= 1 or chargeState <= 4) ) {
233
+			current_state = STATE_DOCKED;
234
+		}
235
+		chargeState = new_chargeState;
236
+		itoa(chargeState, tmp, 10);
237
+		client.publish("roomba/charging", tmp, true);
238
+	}
239
+
240
+	// Reset num_restarts if current draw is over 300mA
241
+	if ( battery_current < -300 ) {
242
+		num_restarts = 0;
243
+	}
244
+
245
+	// Don't try to restart things if we've tried 5 times - we're probably stuck.
246
+	if ( num_restarts > 5 ) {
247
+		current_state = STATE_UNKNOWN;
248
+		client.publish("roomba/status", "Error");
249
+		client.publish("roomba/currentStatus", "Error");
250
+		return;
251
+	}
252
+	
253
+	// Return if less than 40% battery
254
+	if ( current_state == STATE_CLEANING && battery_percent < 40 ) {
255
+		stopCleaning();
256
+	}
257
+
258
+	// If we're cleaning or returning, and the battery current is between 0 and 300mA, something is wrong.
259
+	if ( ( current_state == STATE_CLEANING or current_state == STATE_RETURNING ) && battery_current > -300 && battery_current < 0 ) {
260
+		num_restarts++;
261
+		// If we're over 50% battery, start cleaning again, else search for the dock.
262
+		if ( battery_percent >= 50 ) {
263
+			startCleaning();
264
+			return;
265
+		} else {
266
+			stopCleaning();
267
+			return;
268
+		}
269
+	}
270
+
271
+	// Publish our status to roomba/currentStatus - but only if its different than the last one.
272
+	String newStatus;
273
+	switch (chargeState) {
274
+		case 0:
275
+			if ( current_state == STATE_UNKNOWN ) { newStatus = "Unknown"; };
276
+			if ( current_state == STATE_CLEANING ) { newStatus = "Cleaning"; };
277
+			if ( current_state == STATE_RETURNING ) { newStatus = "Returning to Dock"; };
278
+			break;
279
+
280
+		case 1: newStatus = "Reconditioning"; break;
281
+		case 2: newStatus = "Charging"; break;
282
+		case 3: newStatus = "Trickle Charge"; break;
283
+		case 4: newStatus = "Charged"; break;
284
+		case 5: newStatus = "Charging Fault"; break;
285
+	}
286
+	if ( newStatus != currentStatus ) {
287
+		currentStatus = newStatus;
288
+		client.publish("roomba/currentStatus", currentStatus.c_str(), true);
289
+	}
290
+
291
+	last_status += "getSensors - Success\n";
292
+}
293
+
294
+void StayAwake() {
295
+	last_status += "Pulsing the BRC pin...\n";
296
+	digitalWrite(noSleepPin, LOW);
297
+	delay(100);
298
+	digitalWrite(noSleepPin, HIGH);
299
+}
300
+
301
+void resetRoomba() {
302
+	byte command[] = { 128, 129, 11, 7 };
303
+	digitalWrite(noSleepPin, LOW);
304
+	delay(100);
305
+	digitalWrite(noSleepPin, HIGH);
306
+	Serial.begin(19200);
307
+	SendCommandList( command, 4 );
308
+	delay(500);
309
+	Serial.begin(115200);
310
+	SendCommandList( command, 4 );
311
+	digitalWrite(noSleepPin, LOW);
312
+	delay(100);
313
+	digitalWrite(noSleepPin, HIGH);
314
+}
315
+
316
+void handle_root() {
317
+	String webpage = "<html><head><meta http-equiv=\"refresh\" content=\"5\"></head><body><h3>Roomba stats</h3><ul>";
318
+	webpage += "<li>chargeState: ";
319
+	switch (chargeState) {
320
+		case 0: webpage += "Not Charging"; break;
321
+		case 1: webpage += "Reconditioning"; break;
322
+		case 2: webpage += "Charging"; break;
323
+		case 3: webpage += "Trickle Charge"; break;
324
+		case 4: webpage += "Charged"; break;
325
+		case 5: webpage += "Charging Fault"; break;
326
+	}
327
+	webpage += "</li><li>battery_voltage: ";
328
+	webpage += battery_voltage;
329
+	webpage += " mV</li><li>battery_current: ";
330
+	webpage += battery_current;
331
+	webpage += " mA</li><li>battery_temp: ";
332
+	webpage += battery_temp;
333
+	webpage += " C</li><li>battery_percent: ";
334
+	webpage += battery_percent;
335
+	webpage += " %</li><li>battery_charge: ";
336
+	webpage += battery_charge;
337
+	webpage += " mAh</li><li>battery_capacity: ";
338
+	webpage += battery_capacity;
339
+	webpage += " mAh</li><li>num_restarts: ";
340
+	webpage += num_restarts;
341
+	webpage += "</li><li>current_state: ";
342
+	switch (current_state) {
343
+		case STATE_UNKNOWN: webpage += "Unknown"; break;
344
+		case STATE_CLEANING: webpage += "Cleaning"; break;
345
+		case STATE_RETURNING: webpage += "Returning to Dock"; break;
346
+		case STATE_DOCKED: webpage += "Docked"; break;
347
+	}
348
+	webpage += "</li></ul>Last Status:<br><pre>";
349
+	webpage += last_status;
350
+	webpage += "</pre><br>- <a href=\"/reboot\">Reboot</a><br>- <a href=\"/update\">Update</a><br><br>Update Status:<br><pre>";
351
+	webpage += update_status;
352
+	webpage += "</pre><font size=\"-1\">";
353
+	webpage += ESP.getFullVersion();
354
+	webpage += "</font></body></html>";
355
+	httpServer.send(200, "text/html", webpage);
356
+}
357
+
358
+void reboot() {
359
+	String webpage = "<html><head><meta http-equiv=\"refresh\" content=\"10;url=/\"></head><body>Rebooting</body></html>";
360
+	httpServer.send(200, "text/html", webpage);
361
+	client.publish("roomba/status", "Rebooting");
362
+	httpServer.handleClient();
363
+	client.loop();
364
+	delay(100);
365
+	ESP.restart();
366
+}
367
+
368
+void startCleaning() {
369
+	current_state = STATE_CLEANING;
370
+	byte command[] = { 131, 135, 128 };
371
+	SendCommandList( command, 3 );
372
+	client.publish("roomba/status", "Cleaning");
373
+}
374
+
375
+void stopCleaning() {
376
+	current_state = STATE_RETURNING;
377
+	byte command[] = { 131, 143, 128 };
378
+	SendCommandList( command, 3 );
379
+	client.publish("roomba/status", "Searching for Dock");
380
+}
381
+
382
+void SendCommandList( byte *ptr, byte len ) {
383
+	last_status += "TX:";
384
+	for ( int i = 0; i < len ; i++ ) {
385
+		last_status += " ";
386
+		last_status += ptr[i];
387
+		Serial.write(ptr[i]);
388
+		delay(25);
389
+	}
390
+	last_status += "\n";
391
+}

Loading…
Cancel
Save