diff --git a/Behaviours.h b/Behaviours.h new file mode 100644 index 0000000000000000000000000000000000000000..2a448b84300c3dd2c1495351571b5f444f5c1019 --- /dev/null +++ b/Behaviours.h @@ -0,0 +1,90 @@ +#ifndef BEHAVIOUR_h +#define BEHAVIOUR_h + + + + + +class Behaviour { +protected: + boolean _interruptable = true; + boolean _temp = false; + boolean _priority = false; + boolean _running = false; + String _name = "name"; + + +public: + Behaviour(String name) : _name(name) {}; + ~Behaviour() {}; + + //Can this behaviour be interruped + virtual boolean is_interruptable() { return _interruptable; }; + //Can this behaviour be run quickly without stopping what's going on (e.g. comms, debug) + virtual boolean is_temp() { return _temp; }; + //Should this behaviour override others + virtual boolean is_priority() {return _priority;}; + //Is the behaviour running + virtual boolean is_running() {return _running;}; + //What's the name of this behaviour + virtual String name() {return _name; }; + //Start the behaviour, with arguments (don't know why this can't be virtual?) + virtual String start(String args) {Serial.println("Base start called <"+args+">");}; + //Update the behaviour periodically + virtual void update() {}; + //Start the behaviour, with arguments (don't know why this can't be virtual?) + virtual void stop() { _running = false; }; +}; + +/* + * Example way to make a simple behaviour + */ +class TestBehaviour : public Behaviour { +public: + TestBehaviour(String n) : Behaviour(n) {} + String start(String args) { + return "Test behaviour " + _name + " with (" + args + ")"; + } +}; + + +class BehaviourTable { + Behaviour* behaviours[40]; + + +public: + int num = 0; + BehaviourTable() { + + } + void add(Behaviour *b) { + behaviours[num] = b; + + num++; + } + + Behaviour* get(String n) { + for( int i = 0; i < num; i++ ) { + if( behaviours[i]->name() == n) { return behaviours[i]; } + } + return nullptr; + } +}; + + + + + + + + + + + + + + + + + +#endif diff --git a/ServoBehaviours.h b/ServoBehaviours.h new file mode 100644 index 0000000000000000000000000000000000000000..31b3fdf0b272d65f3924a2f83c0bf4be97713284 --- /dev/null +++ b/ServoBehaviours.h @@ -0,0 +1,61 @@ +#ifndef SERVO_BEHAVIOUR_h +#define SERVO_BEHAVIOUR_h +#include "Arduino.h" +#include "Behaviours.h" + +#include <Servo.h> + +class ServoGoto : public Behaviour { + Servo _servo; + +public: + ServoGoto(Servo servo, String name = "goto") : Behaviour(name), _servo(servo) {} + //ServoMove(Servo servo, String name) : Behaviour(name), _servo(servo) {} + + String start(String args) { + Serial.println("Goto: '"+args+"'"); + int val = args.toInt(); + _servo.write(val); + return ""; + } + +}; + +class ServoWiggle : public Behaviour { + Servo _servo; + int _start_time = 0; + int _wiggle_time = 300; + int _num_wiggles = 5; + int _wiggles = 0; + int _wiggle_angle = 0; + //Calculate wiggle time by multiplying the angle by this... + int _wiggle_factor = 5; + +public: + ServoWiggle(Servo servo, String name, int slowness=3) : Behaviour(name), _servo(servo),_wiggle_factor(slowness) {} + String start(String args) { + _wiggle_angle = args.toInt(); + _wiggles = 0; + _running = true; + _wiggle_time = _wiggle_factor * _wiggle_angle; + return "Wiggling " + String(_num_wiggles) + " times"; + } + + void update() { + int time_since = millis() - _start_time; + if( time_since > _wiggle_time ) { + _wiggles++; + _start_time = millis(); + int angle = ( _wiggles % 2 ) ? (90+_wiggle_angle) : (90-_wiggle_angle); + if( _wiggles > _num_wiggles ) { + angle = 90; + _running = false; + } + Serial.println("Wiggling to: " + String(angle)); + _servo.write(angle); + } + } + +}; + +#endif diff --git a/WallVis.cpp b/WallVis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/WallVis.cpp @@ -0,0 +1 @@ + diff --git a/WallVis.h b/WallVis.h new file mode 100644 index 0000000000000000000000000000000000000000..957b85eee3c56b7f88e7233e9a8c78e17b49b35d --- /dev/null +++ b/WallVis.h @@ -0,0 +1,199 @@ +#ifndef WALLVIS_H +#define WALLVIS_H +#include "Arduino.h" +#include "Behaviours.h" +#include "ServoBehaviours.h" + +#include <ESP8266WiFi.h> +#include "Adafruit_MQTT.h" +#include "Adafruit_MQTT_Client.h" + +#define WLAN_SSID "WallVisNet" //"...your SSID..." +#define WLAN_PASS "wallvisAP" // "...your password..." + +/************************* Adafruit.io Setup *********************************/ + +/* +#define AIO_SERVER "192.168.4.1" //"io.adafruit.com" +#define AIO_SERVERPORT 1883 // use 8883 for SSL +#define AIO_USERNAME "" //"...your AIO username (see https://accounts.adafruit.com)..." +#define AIO_KEY "" //"...your AIO key..." +*/ + +#define MQTT_topic "new001" + +void* current_wallvis; + +void test_callback(char *data, uint16_t len) { + //((WallVis*)current_wallvis)-> + Serial.println("Got testt: "); + Serial.println(data); +} + +class WallVis { + BehaviourTable _behaviours; + char* _ssid; + char* _wifi_pass; + char* _id; + char* _server; + int _port; + Behaviour* _active = nullptr; + int _loop_time = 5; + Adafruit_MQTT_Client* _mqtt; + Adafruit_MQTT_Subscribe* _device_subscription; + WiFiClient* _client; + + + + + +public: + WallVis(char* id, char* ssid="WallVisNet", char* wifi_pass="wallvisAP", + char* server="192.168.4.1",int port=1883) : _id(id), _server(server), _port(port), _ssid(ssid), _wifi_pass(wifi_pass) {} ; + + void command_callback(char *data, uint16_t len) { + Serial.println("Got command: "); + Serial.println(data); + } + + + + void init() { + current_wallvis = this; + Serial.println("Initialising"); + Serial.println(F("Adafruit MQTT demo")); + + WiFi.mode(WIFI_STA); + + // Connect to WiFi access point. + Serial.println(); Serial.println(); + Serial.print("Connecting to "); + Serial.println(_ssid); + + WiFi.begin(_ssid, _wifi_pass); + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + Serial.println(); + + Serial.println("WiFi connected"); + Serial.println("IP address: "); Serial.println(WiFi.localIP()); + + _client = new WiFiClient(); + _mqtt = new Adafruit_MQTT_Client(_client, _server, _port, "" /* mqttt username */, "" /* mqtt pass*/); + _device_subscription = new Adafruit_MQTT_Subscribe(_mqtt, _id); + _device_subscription->setCallback(test_callback); + + // Setup MQTT subscription for onoff feed. + // mqtt.subscribe(&onoffbutton); + _mqtt->subscribe(_device_subscription); + MQTT_connect(); + + Serial.println("Init finished"); + + } + + + + void add(Behaviour *b) { + _behaviours.add(b); + } + + void vis_loop() { + int loop_start_time = millis(); + serial_command(); + //mqtt_command(); + if( _active ) { + Serial.println("Updating "+_active->name()); + _active -> update(); + if( ! _active->is_running() ) _active = nullptr; + } + int loop_time_taken = millis()-loop_start_time; + if( loop_time_taken < _loop_time ) { + delay( _loop_time - loop_time_taken ); + } + } + + void serial_command() { + if( Serial.available() ) { + String cmd = Serial.readStringUntil('\n'); + Serial.println(process(cmd)); + } + } + + void mqtt_command() { + MQTT_connect(); //ensure connection + + Adafruit_MQTT_Subscribe *subscription; + while ((subscription = _mqtt->readSubscription(50))) { + if (subscription == _device_subscription) { + Serial.print(F("Got: ")); + Serial.println((char *)_device_subscription->lastread); + Serial.println(process((char *)_device_subscription->lastread)); + } + } + } + + + + String process(String input) { + int index = input.indexOf(" "); + String command = ""; + String args = ""; + + if( index) { + command = input.substring(0,index); + args = input.substring(index+1); + } else { + command = input; + } + return process_command(command, args); + } + + String process_command(String command, String args) { + Serial.println("Processing <"+command+"> <"+args+">"); + Behaviour* b = _behaviours.get(command); + if(b) { + if( _active ) { _active->stop(); } + Serial.println( "Found behaviour: <"+command+">" ); + _active = b; + return( b->start(args) ); + } else { + return "Couldn't process command: " + command; + } + } + + // Function to connect and reconnect as necessary to the MQTT server. + // Should be called in the loop function and it will take care if connecting. + void MQTT_connect() { + int8_t ret; + + // Stop if already connected. + if (_mqtt->connected()) { + return; + } + + Serial.print("Connecting to MQTT... "); + + uint8_t retries = 3; + while ((ret = _mqtt->connect()) != 0) { // connect will return 0 for connected + Serial.println(_mqtt->connectErrorString(ret)); + Serial.println("Retrying MQTT connection in 5 seconds..."); + _mqtt->disconnect(); + delay(5000); // wait 5 seconds + retries--; + if (retries == 0) { + // basically die and wait for WDT to reset me + while (1); + } + } + Serial.println("MQTT Connected!"); + } + +}; + + + + +#endif diff --git a/examples/SimpleNode/SimpleNode.ino b/examples/SimpleNode/SimpleNode.ino new file mode 100644 index 0000000000000000000000000000000000000000..b5f25a62a069e0c6b359cac0a2ac619a474ea33a --- /dev/null +++ b/examples/SimpleNode/SimpleNode.ino @@ -0,0 +1,33 @@ +#include <Servo.h> + +#include <WallVis.h> +#include <Behaviours.h> + +WallVis vis("new001"); + +Servo s1 = Servo(); + + +void setup() +{ + s1.attach(D3); + Serial.begin(115200); + Serial.setTimeout(100); + Behaviour* hello = new TestBehaviour("hello"); + //Behaviour* goodbye = new TestBehaviour("goodbye"); + //vis.add(hello); + //vis.add(goodbye); + vis.add(new ServoWiggle(s1, "wiggle") ); + vis.add(new ServoWiggle(s1, "slow_wiggle", 10) ); + vis.add(new ServoWiggle(s1, "fast_wiggle", 1) ); + vis.add(new ServoGoto(s1) ); + vis.init(); + s1.write(90); +} + + +void loop() +{ + vis.vis_loop(); + delay(50); +}