diff --git a/README.md b/README.md
index 1435e90..b95976e 100644
--- a/README.md
+++ b/README.md
@@ -30,39 +30,45 @@ vi include/secrets.h
pio run
```
+Make a note of the gateway's MAC address:
+
+```bash
+Initialized [82:7d:3a:79:14:79]
+```
+
**Note:** Bricks currently requires a WiFi network that uses channel 1.
### 3. Create some bricks
-[WIP library here](/examples).
-For example a button:
+[WIP catalogue here](/examples).
+For example a button and an LED:
```bash
+export PLATFORMIO_BUILD_FLAGS="'-DBRICKS_GATEWAY_MAC=\"82:7d:3a:79:14:79\"'"
+
cd examples/button
pio run
-```
-and an LED:
-
-```bash
cd examples/led
pio run
```
-### 4. Scan for bricks
+### 4. Communicate with bricks using MQTT
+
+Bricks announce themselves and their MAC addresses when they come online:
```mqtt
-bricks/gateway/scan
+bricks/in/ee:fa:bc:8e:89:1e/pong: Button
+bricks/in/ee:fa:bc:8e:89:8f/pong: LED
```
-This will configure all active bricks to use the gateway,
-each responding with a "pong" containing their MAC address and name:
+Use the MAC address to send messages to the bricks:
```mqtt
-bricks/in/ee:fa:bc:8e:89:1e/pong: Button
+bricks/out/ee:fa:bc:8e:89:8f/setPattern: 1
```
-### 5. Connect things in NodeRED
+### 5. Connect bricks in NodeRED
Here is a simple example that allows a button brick to control an LED
brick:
@@ -70,19 +76,14 @@ brick:
-### Todo
-
-- [x] Button
-- [ ] LED
-- [ ] Try out [Wemos D1 hack](https://www.youtube.com/watch?v=rfPwOtoGO4E)
-
## Software
### Todo
- [ ] TravisCI
- [ ] Turn "setRotation" into an action instead for LED Matrix
- [ ] Move "ack" to top of stack, run actions in reverse, or split actions
-- [ ] Use advertising instead of "scan" to claim bricks
+- [ ] Node-RED list of bricks
+- [ ] Verify tests after gateway hardcoding
### Nice to haves
- [ ] Fix errors raised by `pio check` (mainly passing `Message` by value)
@@ -91,10 +92,14 @@ brick:
- [ ] More tests
- [ ] Make aliexpress ble button send notifications
- [ ] Idea: Move sender macAddr into message to reduce params to 1?
-- [ ] Use same system for defining mqtt responses (instead of hardcoded "scan")
- ```
- // Connect mqtt event stream
- gEvents.init();
- gEvents.events[0] = new ScanEvent();
- gEvents.events[1] = new BroadcastEvent();
- ```
+
+## Hardware
+
+### Todo
+- [ ] Low profile headers
+- [ ] Finish case
+- [ ] Nicer stickers
+- [ ] Button
+- [ ] LED
+- [ ] Try out [Wemos D1 hack](https://www.youtube.com/watch?v=rfPwOtoGO4E)
+
diff --git a/examples/README.md b/examples/README.md
index c2a9e08..0639337 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -1,8 +1,7 @@
# Brick Examples
- [Gateway](gateway)
-- [Button (realtime)](button)
-- [Button (sleeps)](button-sleep)
+- [Button](button)
- [LED](led)
- [LED RGB](led-rgb)
- [LED 8x8 Matrix](led-matrix)
@@ -14,12 +13,13 @@
### Inbox
-| key | description | values |
-|------------|-------------------------------------------|----------------------|
-| * | Responds with `ack:` to all messages | |
-| ping | Saves gateway MAC, responds with `pong` | |
-| sleep | Sleep for `value` seconds | 0 (forever), 1-13612 |
-| getBattery | Ask to send battery value | |
+| key | description | values |
+|------------|---------------------------------------------------------------------------|----------------------|
+| * | Responds with `ack:` to all messages | |
+| ping | Saves gateway MAC, responds with `pong` | |
+| sleep | Sleep for `value` seconds | 0 (forever), 1-13612 |
+| getBattery | Ask to send battery value | |
+| setOta | Allows `pio run -t upload --upload-port 192.168.4.1` when connected to AP | |
### Outbox
diff --git a/examples/ble/src/main.cpp b/examples/ble/src/main.cpp
index 7cdee22..d389a56 100644
--- a/examples/ble/src/main.cpp
+++ b/examples/ble/src/main.cpp
@@ -8,7 +8,7 @@ using namespace Bricks;
#include
BLEScan *pBLEScan;
-const int8_t MINIMUM_RSSI = -70;
+const int8_t MINIMUM_RSSI = -80;
class BLECallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice* device) {
diff --git a/examples/button-sleep/README.md b/examples/button-sleep/README.md
deleted file mode 100644
index 272e8d6..0000000
--- a/examples/button-sleep/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-# Button - Sleep
-
-"Sleepable" button/trigger.
-Should be put to sleep "permanently" and use RST wake-up as trigger.
diff --git a/examples/button-sleep/platformio.ini b/examples/button-sleep/platformio.ini
deleted file mode 100644
index 41ddb10..0000000
--- a/examples/button-sleep/platformio.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[platformio]
-default_envs = d1_mini
-extra_configs =
- ../../shared.ini
-
-[env]
-lib_extra_dirs = ../../
-lib_deps =
- ${common.lib_deps}
diff --git a/examples/button-sleep/src/main.cpp b/examples/button-sleep/src/main.cpp
deleted file mode 100644
index b21f720..0000000
--- a/examples/button-sleep/src/main.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-// Bricks
-#include
-#include
-#include
-using namespace Bricks;
-
-void setup() {
- // Logging
- Serial.begin(115200);
- Log.begin(LOG_LEVEL_NOTICE, &Serial);
-
- // Configure ESPNow
- gBrick.init();
-
- // Configure inbox
- gInbox.init("Button");
-}
-
-void loop() {
- gInbox.loop();
-}
diff --git a/examples/button/README.md b/examples/button/README.md
index 8a859d1..a4e806d 100644
--- a/examples/button/README.md
+++ b/examples/button/README.md
@@ -1,7 +1,7 @@
# Button
-"Always on" button.
-Very responsive but will consume battery/should probably be plugged in.
+If plugged in can use `pressed/release` messages.
+Can also be put to sleep and use RST wake-up as trigger.
## Outbox
diff --git a/examples/button/platformio.ini b/examples/button/platformio.ini
index d573937..8c577ec 100644
--- a/examples/button/platformio.ini
+++ b/examples/button/platformio.ini
@@ -1,5 +1,5 @@
[platformio]
-default_envs = d1_mini_pro
+default_envs = d1_mini
extra_configs =
../../shared.ini
diff --git a/examples/button/src/main.cpp b/examples/button/src/main.cpp
index 114b906..c927393 100644
--- a/examples/button/src/main.cpp
+++ b/examples/button/src/main.cpp
@@ -23,7 +23,7 @@ void setup() {
gBrick.init();
// Configure inbox
- gInbox.init("Button (Realtime)");
+ gInbox.init("Button");
}
void loop() {
@@ -34,4 +34,6 @@ void loop() {
if(button.onReleased()) {
gOutbox.send("released");
}
+
+ gInbox.loop();
}
diff --git a/examples/gateway/platformio.ini b/examples/gateway/platformio.ini
index 80b5df5..4859296 100644
--- a/examples/gateway/platformio.ini
+++ b/examples/gateway/platformio.ini
@@ -6,6 +6,7 @@ extra_configs =
[env]
build_flags=
-include include/secrets.h
+ -DBRICKS_GATEWAY_MAC=\"00:00:00:00:00:00\"
lib_extra_dirs = ../../
lib_deps =
${common.lib_deps}
diff --git a/library.json b/library.json
index 0592127..7e81816 100644
--- a/library.json
+++ b/library.json
@@ -8,7 +8,6 @@
},
"dependencies": {
"ArduinoLog": "~1.0.3",
- "EEPROM": ">0",
"PubSubClient": "~2.8",
"WifiEspNow": "~0.0.20190814"
},
diff --git a/shared.ini b/shared.ini
index 394c788..dcc1bbd 100644
--- a/shared.ini
+++ b/shared.ini
@@ -2,7 +2,6 @@
[common]
lib_deps =
ArduinoLog
- EEPROM
PubSubClient
WifiEspNow
diff --git a/src/Bricks.Brick.cpp b/src/Bricks.Brick.cpp
index 467deaa..4a24b97 100644
--- a/src/Bricks.Brick.cpp
+++ b/src/Bricks.Brick.cpp
@@ -4,17 +4,30 @@ namespace Bricks {
void Brick::init(const WiFiMode_t wifiMode) {
// Configure Wi-Fi
WiFi.mode(wifiMode);
+ WiFi.softAP("ESPNOW", NULL, BRICKS_WIFI_CHANNEL, true, 0); // hide AP
// Connect ESPNOW
if (WifiEspNow.begin()) {
- String macStr = WiFi.softAPmacAddress();
- macStr.toLowerCase();
- Log.notice("ESPN: Initialized [%s]" CR, macStr.c_str());
+ logMac(wifiMode);
}
else {
Log.error("ESPN: Error initializing" CR);
}
}
+ void Brick::logMac(WiFiMode_t wifiMode) {
+ String macStr;
+
+ if(wifiMode == WIFI_STA) {
+ macStr = WiFi.macAddress();
+ }
+ else {
+ macStr = WiFi.softAPmacAddress();
+ }
+
+ macStr.toLowerCase();
+ Log.notice("ESPN: Initialized [%s]" CR, macStr.c_str());
+ }
+
Brick gBrick = Brick();
}
diff --git a/src/Bricks.Brick.h b/src/Bricks.Brick.h
index 226d209..e2d9e84 100644
--- a/src/Bricks.Brick.h
+++ b/src/Bricks.Brick.h
@@ -9,10 +9,14 @@
#endif
#include
+#include
+
namespace Bricks {
class Brick {
public:
- void init(const WiFiMode_t wifiMode = WIFI_AP);
+ void init(const WiFiMode_t wifiMode = WIFI_AP); // AP is more stable that STA when communication with AT_STA
+ private:
+ void logMac(WiFiMode_t wifiMode);
};
extern Brick gBrick;
diff --git a/src/Bricks.Constants.h b/src/Bricks.Constants.h
index 882ccef..5a3826c 100644
--- a/src/Bricks.Constants.h
+++ b/src/Bricks.Constants.h
@@ -2,12 +2,9 @@
#define BRICKS_CONSTANTS_H
#define BRICKS_WIFI_CHANNEL 1
-#define BRICKS_NAME_PREFIX "Brick - "
-#define BRICKS_PING_ACTION "ping"
#define MAC_FORMAT "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx"
#define MAC_ADDR_SIZE 6
#define MAC_STR_SIZE 18
-#define MAC_UNSET {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
#define MICROSECONDS 1000000
#define KEY_SIZE 20
diff --git a/src/Bricks.Events.cpp b/src/Bricks.Events.cpp
index 1c97c86..1df0a7b 100644
--- a/src/Bricks.Events.cpp
+++ b/src/Bricks.Events.cpp
@@ -46,15 +46,10 @@ namespace Bricks {
char *value = (char *) bytes;
Log.trace("MQTT: <- %s: %s" CR, topic, value);
- if(strcmp(BRICKS_MESSAGES_SCAN, topic) == 0) {
- scanForBricks();
- }
- else {
- uint8_t macAddr[MAC_ADDR_SIZE];
- char key[KEY_SIZE];
- parseTopic(topic, macAddr, key);
- gOutbox.send(macAddr, key, value);
- }
+ uint8_t macAddr[MAC_ADDR_SIZE];
+ char key[KEY_SIZE];
+ parseTopic(topic, macAddr, key);
+ gOutbox.send(macAddr, key, value);
}
void Events::parseTopic(const char *topic, uint8_t *macAddr, char *key) {
@@ -83,7 +78,6 @@ namespace Bricks {
if(mqtt.connect(BRICKS_MQTT_CLIENT, BRICKS_MQTT_USER, BRICKS_MQTT_PASSWORD)) {
Log.notice("MQTT: Connected" CR);
subscribe(BRICKS_MESSAGES_OUT "/#");
- subscribe(BRICKS_MESSAGES_SCAN);
}
else {
Log.warning("MQTT: Failed [%s]. Retrying in 5 secs" CR, mqtt.state());
@@ -97,21 +91,5 @@ namespace Bricks {
Log.trace("MQTT: Subscribed [%s]" CR, topic);
}
- void Events::scanForBricks() {
- Log.notice("WIFI: Scanning for Bricks" CR);
- const uint8_t scanResults = WiFi.scanNetworks();
-
- for(int i = 0; i < scanResults; ++i) {
- if(WiFi.SSID(i).indexOf(BRICKS_NAME_PREFIX) == 0) {
- Log.trace("WIFI: Brick found on channel %d" CR, WiFi.channel(i));
- gOutbox.send(WiFi.BSSID(i), BRICKS_PING_ACTION);
- }
- }
-
- WiFi.scanDelete();
- Log.notice("WIFI: Scan complete" CR);
- gEvents.publish(BRICKS_MESSAGES_SCAN "/done");
- }
-
Events gEvents = Events();
}
diff --git a/src/Bricks.Events.h b/src/Bricks.Events.h
index b796dc7..ad6189e 100644
--- a/src/Bricks.Events.h
+++ b/src/Bricks.Events.h
@@ -27,7 +27,6 @@
#define BRICKS_MESSAGES_IN BRICKS_MQTT_TOPIC_PREFIX "/in"
#define BRICKS_MESSAGES_OUT BRICKS_MQTT_TOPIC_PREFIX "/out"
-#define BRICKS_MESSAGES_SCAN BRICKS_MQTT_TOPIC_PREFIX "/gateway/scan"
namespace Bricks {
class Events {
@@ -48,7 +47,6 @@ namespace Bricks {
void connectWiFi();
void connectMQTT();
void subscribe(const char *topic);
- static void scanForBricks();
};
extern Events gEvents;
diff --git a/src/Bricks.Inbox.cpp b/src/Bricks.Inbox.cpp
index 64f465c..28bfd4b 100644
--- a/src/Bricks.Inbox.cpp
+++ b/src/Bricks.Inbox.cpp
@@ -2,10 +2,9 @@
namespace Bricks {
void Inbox::init(const char *name) {
- actions[3] = new OtaAction();
- actions[4] = new ListAction();
- actions[5] = new PongAction(name);
- actions[6] = new StoreGatewayAction();
+ actions[4] = new OtaAction();
+ actions[5] = new ListAction();
+ actions[6] = new PongAction(name);
actions[7] = new SleepAction();
actions[8] = new BatteryAction();
actions[9] = new AckAction();
diff --git a/src/Bricks.Inbox.h b/src/Bricks.Inbox.h
index 2319ad2..97ae50a 100644
--- a/src/Bricks.Inbox.h
+++ b/src/Bricks.Inbox.h
@@ -16,7 +16,6 @@
#include
#include
#include
-#include
# define MAX_ACTIONS 10
diff --git a/src/Bricks.OtaAction.cpp b/src/Bricks.OtaAction.cpp
index 2d8f8a2..483b26f 100644
--- a/src/Bricks.OtaAction.cpp
+++ b/src/Bricks.OtaAction.cpp
@@ -10,7 +10,7 @@ namespace Bricks {
void OtaAction::callback(const uint8_t *macAddr, const Message message) {
initOta();
- gOutbox.send(macAddr, "ota", WiFi.softAPIP().toString().c_str());
+ startAP();
}
void OtaAction::initOta() {
@@ -42,4 +42,9 @@ namespace Bricks {
});
ArduinoOTA.begin();
}
+
+ void OtaAction::startAP() {
+ WiFi.mode(WIFI_AP);
+ WiFi.softAP("Brick - OTA", NULL, BRICKS_WIFI_CHANNEL, false, 1);
+ }
}
diff --git a/src/Bricks.OtaAction.h b/src/Bricks.OtaAction.h
index e8d1bf6..36aa7f6 100644
--- a/src/Bricks.OtaAction.h
+++ b/src/Bricks.OtaAction.h
@@ -14,6 +14,7 @@ namespace Bricks {
void callback(const uint8_t *macAddr, const Message message);
private:
void initOta();
+ void startAP();
};
}
#endif
diff --git a/src/Bricks.Outbox.cpp b/src/Bricks.Outbox.cpp
index 035eb9a..c853fda 100644
--- a/src/Bricks.Outbox.cpp
+++ b/src/Bricks.Outbox.cpp
@@ -1,6 +1,10 @@
#include "Bricks.Outbox.h"
namespace Bricks {
+ Outbox::Outbox() {
+ setGatewayMac();
+ }
+
void Outbox::send(const uint8_t *macAddr, const char* key, const char* value) {
pair(macAddr);
@@ -47,14 +51,9 @@ namespace Bricks {
}
}
- void Outbox::setGatewayMac(const uint8_t *macAddr) {
- for (int i = 0; i < MAC_ADDR_SIZE; ++i) {
- gatewayMac[i] = macAddr[i];
- }
-
- char macStr[MAC_STR_SIZE];
- Bricks::Utils::macToStr(gatewayMac, macStr);
- Log.notice("BRIC: Current gateway MAC [%s]" CR, macStr);
+ void Outbox::setGatewayMac() {
+ sscanf(BRICKS_GATEWAY_MAC, MAC_FORMAT,
+ &gatewayMac[0], &gatewayMac[1], &gatewayMac[2], &gatewayMac[3], &gatewayMac[4], &gatewayMac[5]);
}
Outbox gOutbox = Outbox();
diff --git a/src/Bricks.Outbox.h b/src/Bricks.Outbox.h
index ac951ff..49bb55e 100644
--- a/src/Bricks.Outbox.h
+++ b/src/Bricks.Outbox.h
@@ -11,13 +11,13 @@
namespace Bricks {
class Outbox {
public:
- Outbox() {}
+ Outbox();
void send(const uint8_t *macAddr, const char *key, const char *value = "");
void send(const char *key, const char *value = "");
- void setGatewayMac(const uint8_t *macAddr);
private:
void pair(const uint8_t *macAddr);
- uint8_t gatewayMac[MAC_ADDR_SIZE] = MAC_UNSET;
+ void setGatewayMac();
+ uint8_t gatewayMac[MAC_ADDR_SIZE];
};
extern Outbox gOutbox;
diff --git a/src/Bricks.PongAction.cpp b/src/Bricks.PongAction.cpp
index 498a902..0a8b84d 100644
--- a/src/Bricks.PongAction.cpp
+++ b/src/Bricks.PongAction.cpp
@@ -1,19 +1,12 @@
#include
namespace Bricks {
- PongAction::PongAction(const char *name) : Action(BRICKS_PING_ACTION) {
+ PongAction::PongAction(const char *name) : Action("ping") {
this->name = name;
- advertise();
gOutbox.send("pong", name);
}
void PongAction::callback(const uint8_t *macAddr, const Message message) {
gOutbox.send(macAddr, "pong", name);
}
-
- void PongAction::advertise() {
- char apName[50]; // Need unique name?
- sprintf(apName, BRICKS_NAME_PREFIX "%s", WiFi.softAPmacAddress().c_str());
- WiFi.softAP(apName, NULL, BRICKS_WIFI_CHANNEL);
- }
}
diff --git a/src/Bricks.PongAction.h b/src/Bricks.PongAction.h
index f5b1066..1aa3957 100644
--- a/src/Bricks.PongAction.h
+++ b/src/Bricks.PongAction.h
@@ -3,7 +3,6 @@
#include
#include
-#include
#include
namespace Bricks {
@@ -12,7 +11,6 @@ namespace Bricks {
PongAction(const char *name = "New Brick");
void callback(const uint8_t *macAddr, const Message message);
private:
- void advertise();
const char *name;
};
}
diff --git a/src/Bricks.StoreGatewayAction.cpp b/src/Bricks.StoreGatewayAction.cpp
deleted file mode 100644
index 72c8290..0000000
--- a/src/Bricks.StoreGatewayAction.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include
-
-namespace Bricks {
- StoreGatewayAction::StoreGatewayAction() : Action(BRICKS_PING_ACTION) {
- EEPROM.begin(MAC_ADDR_SIZE);
- readMac();
- }
-
- void StoreGatewayAction::callback(const uint8_t *macAddr, const Message message) {
- writeMac(macAddr);
- }
-
- void StoreGatewayAction::writeMac(const uint8_t *macAddr) {
- Log.notice("EEPR: Storing gateway MAC" CR);
-
- for (int i = 0; i < MAC_ADDR_SIZE; ++i) {
- EEPROM.write(i, macAddr[i]);
- }
- EEPROM.commit();
-
- gOutbox.setGatewayMac(macAddr);
- }
-
- void StoreGatewayAction::readMac() {
- Log.notice("EEPR: Reading gateway MAC" CR);
-
- uint8_t macAddr[MAC_ADDR_SIZE];
-
- for (int i = 0; i < MAC_ADDR_SIZE; ++i) {
- macAddr[i] = EEPROM.read(i);
- }
-
- gOutbox.setGatewayMac(macAddr);
- }
-}
diff --git a/src/Bricks.StoreGatewayAction.h b/src/Bricks.StoreGatewayAction.h
deleted file mode 100644
index 3872526..0000000
--- a/src/Bricks.StoreGatewayAction.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef BRICKS_STORE_GATEWAY_ACTION_H
-#define BRICKS_STORE_GATEWAY_ACTION_H
-
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-namespace Bricks {
- class StoreGatewayAction : public Action {
- public:
- StoreGatewayAction();
- void callback(const uint8_t *macAddr, const Message message);
- private:
- void writeMac(const uint8_t *macAddr);
- void readMac();
- };
-}
-#endif
diff --git a/test/inbox/test_inbox.cpp b/test/inbox/test_inbox.cpp
index bdc1b1a..078a480 100644
--- a/test/inbox/test_inbox.cpp
+++ b/test/inbox/test_inbox.cpp
@@ -3,7 +3,6 @@
#include
#include
#include
-#include
using namespace Bricks;
void setUp(void) {
@@ -20,15 +19,6 @@ void test_pong() {
gInbox.process(macAddr, message);
}
-void test_store_gateway() {
- const uint8_t macAddr[] = {0x98, 0xF4, 0xAB, 0x6C, 0xE6, 0xB5};
- Message message;
- strcpy(message.key, "ping");
-
- gInbox.actions[0] = new StoreGatewayAction();
- gInbox.process(macAddr, message);
-}
-
void test_list_actions() {
gInbox.actions[0] = new PongAction();
@@ -40,7 +30,6 @@ void setup() {
UNITY_BEGIN();
RUN_TEST(test_pong);
- RUN_TEST(test_store_gateway);
RUN_TEST(test_list_actions);
UNITY_END();
}