-
Notifications
You must be signed in to change notification settings - Fork 23
Library Refactor Overview
This library, as it stands now, works alright. But I'm after something a little bit more standardized, solid, and easy to use.
Here are the goals I want to see happen for this library
- Sketches only require one #include
- Clean, modular support for any number of backpacks
- Ability for a Lead Scout to be flashed once, and all MQTT support works transparently regardless of other scouts and the code running on them.
The general class diagram rolling around in my head like a BB in a boxcar is the following:
PinoccioClass handles all the basic stuff--board temperature, battery/power, RNG.
class PinoccioClass {
public:
PinoccioClass();
~PinoccioClass();
void init();
void loop();
float getTemperature();
bool isBatteryCharging();
float getBatteryVoltage();
void enableBackpackVcc();
void disableBackpackVcc();
void getBackpacks();
void getRandomNumber();
protected:
uint16_t randomNumber;
Backpack backpacks[3]; // hardwired at 3, could be higher
};
The PinoccioScout class inherits from PinoccioClass, and handles all the mesh network stuff. If you wanted a truly standalone Pinoccio board doing something, you could still use PinoccioClass directly, and essentially leave the radio off, and wouldn't use this class.
The publish and subscribe methods would send messages directly to the Lead Scout, and act as an MQTT client. sendMessage and listenForMessage are specifically for the mesh radio. This lets you use the latter two methods for direct wireless between two boards, and the former two for pushing data/retrieving data from the web. publish and subscribe would use the sendMessage method, but would only send the message to the Lead Scout.
class PinoccioScout : public PinoccioClass {
public:
PinoccioScout();
~PinoccioScout();
void init();
void loop();
bool publish(char* topic, char* payload, int size);
bool subscribe(char*, bool (*handler)(NWK_DataInd_t *msg));
bool sendMessage(NWK_DataReq_t *msg);
bool listenForMessage(uint8_t id, bool (*handler)(NWK_DataInd_t *msg));
friend class LeadScout;
protected:
uint16_t leadScoutAddress;
};
And lastly, the PinoccioLeadScout, inheriting from PinoccioScout. I know what you're all thinking, b/c I was thinking it too. All that OOP design anti-patterns with deep nests of inheritance vs. composition. However, in this situation, a Lead Scout really is a Scout, and a Scout really is a Pinoccio board. Each needs the functionality of the parent, so in this case I think it's alright. Always open to thoughts and suggestions though.
publishScoutToServer and subscribeScoutToServer would be methods that actually publish or subscribe to the remote MQTT server, based on messages received over the mesh radio from publish or subscribe methods called from another Scout.
The publishTroopMetadataToServer is a helper method that would infrequently publish metadata about the entire troop to the MQTT broker. For instance, whenever a Scout first connects to a Lead Scout, the Lead Scout could publish a "Scout joined" message to a metadata MQTT channel. More details on this later, but an example output of aggregated data that would show up from this method call can be seen here
class PinoccioLeadScout : public PinoccioScout {
public:
PinoccioLeadScout();
~PinoccioLeadScout();
void init();
void loop();
bool publishScoutToServer(uint16_t scoutAddress, char* topic, char* payload, int size);
bool subscribeScoutToServer(uint16_t scoutAddress, char* topic);
bool publishTroopMetadataToServer(char* topic, char* payload, int size);
protected:
Client netClient; // wifi client
mqttClient mqtt;
Scout scouts[NWK_ROUTE_TABLE_SIZE];
};
One issue that we'll have to tackle is managing subscriptions on the Lead Scout, made by other Scouts in the troop. The Lead Scout would need to keep an internal table of what channels each Scout is subscribed to, and route inbound message from the MQTT broker accordingly.
The problem we run into is that we have limited RAM available on the Lead Scout--32k bytes only. And so we'll have to be careful about how we track that locally.
These classes, I fully expect to be composition based rather than inherited. Each PinoccioClass instance will have an array of attached backpacks (based on a tiny microcontroller on each shield to identify itself to any Pinoccio it's attached to.)
Each Backpack should have its own class to handle its specifics. Right now this is the list of currently developed Backpacks:
- Environmental/Solar
- Motion
- MIDI
- Security
- E-Paper
- Bluetooth
- Infrared
- 12 Channel PWM/LED
And here's what the Backpack class is looking like. Specific classes for particular backpacks would inherit from this and add their own functionality.
class PinoccioBackpack {
public:
PinoccioBackpack();
~PinoccioBackpack();
void init();
void loop();
protected:
uint_16 family;
uint_32 id;
};