|
/** |
|
* Lego (Powered Up) train control from Home Assistant / MQTT with BellRing |
|
* |
|
* Licence: GPLv3 |
|
* |
|
* needed libraries: |
|
* legoino https://github.com/corneliusmunz/legoino |
|
* > 1.1.0, tested with commit 4daae4f683b087b8c443a4c813934e3dfff41d69 |
|
* home-assistant-integration https://github.com/dawidchyrzynski/arduino-home-assistant |
|
* 1.3.0 |
|
* DFRobotDFPlayerMini https://github.com/DFRobot/DFRobotDFPlayerMini/ |
|
*/ |
|
|
|
/** HUB led signification |
|
* Flashing white light with short flashes. It is the pareo mode. Pressing the green button tries to connect via Bluetooth for 20 seconds |
|
* Flashing white light with long blinks. The device is resetting |
|
* Permanent blue light. Bluetooth has been connected and everything works fine |
|
* Orange light flashing. Low battery. In this case there are 6 AAA batteries (LR03 at 1,5V) |
|
* Red, green, blue flashing light. The application of the tablet or mobile has forced the firmware update of the Move Hub. The color of the blink will alternate. According the official page the firmware update should take no more than 15 minutes |
|
* |
|
* source: https://www.ikkaro.com/en/move-hub/ |
|
*/ |
|
|
|
// comment that to remove DFPlayer mini sound management |
|
#define DFPLAYER |
|
|
|
#include <WiFi.h> |
|
#include <ArduinoHA.h> |
|
#include "Lpf2Hub.h" |
|
|
|
#ifdef DFPLAYER |
|
// audio |
|
#include "DFRobotDFPlayerMini.h" |
|
HardwareSerial mySoftwareSerial(1); |
|
DFRobotDFPlayerMini myDFPlayer; |
|
uint8_t volume = 10; |
|
#endif |
|
|
|
// constants |
|
// hardcoded values are baaaaaad, we should use something like WiFiManager |
|
const char* ssid = "MySSID"; |
|
const char* password = "SecretPassword"; |
|
const char* mqtt_broker = "192.168.1.20"; |
|
const uint16_t mqtt_port = 1883; |
|
const char* uniqId = "LegoTramway"; |
|
const uint8_t led = 22; // builtin led, may replace by LED_BUILTIN |
|
|
|
// globals |
|
WiFiClient client; |
|
HADevice device(uniqId); |
|
HAMqtt mqtt(client, device); |
|
HASwitch moteur("tram_moteur"); // motor control |
|
HANumber inSpeed("tram_speed"); // motor speed |
|
|
|
#ifdef DFPLAYER |
|
HAButton buttonPlay("tram_play"); // play the sound |
|
HANumber inVolume("tram_volume"); // volume for the sound |
|
#endif |
|
|
|
int32_t speed = 20; // default tram speed |
|
|
|
// create a hub instance |
|
Lpf2Hub myTrainHub; |
|
// motor is on port A |
|
byte port = (byte)PoweredUpHubPort::A; |
|
|
|
// callback for motor on/off |
|
void onMotorCommand(bool state, HASwitch* sender) { |
|
Serial.print("switch: "); |
|
Serial.println(state); |
|
|
|
if (myTrainHub.isConnected()) { |
|
if (state) { |
|
myTrainHub.setBasicMotorSpeed(port, speed); |
|
} else { |
|
myTrainHub.stopBasicMotor(port); |
|
} |
|
sender->setState(state); // report state back to the Home Assistant |
|
} |
|
} |
|
|
|
// callback for input number speed change |
|
void onSpeedCommand(HANumeric number, HANumber* sender) { |
|
if (number.isSet()) { |
|
speed = number.toInt32(); |
|
sender->setState(number); // report the selected option back to the HA panel |
|
Serial.print("set speed: "); |
|
Serial.println(speed); |
|
} |
|
} |
|
|
|
#ifdef DFPLAYER |
|
// callback for play button |
|
void onPlayCommand(HAButton* sender) { |
|
// play |
|
Serial.println("Play..."); |
|
myDFPlayer.play(1); //Play the first mp3 |
|
|
|
} |
|
// callback for volume slider |
|
void onVolumeCommand(HANumeric number, HANumber* sender) { |
|
if (number.isSet()) { |
|
volume = number.toUInt8(); |
|
myDFPlayer.volume(volume); //Set volume value (0~30). |
|
sender->setState(number); // report the selected option back to the HA panel |
|
Serial.print("set vol: "); |
|
Serial.println (volume); |
|
} |
|
} |
|
#endif |
|
|
|
// set availab for tramway entities |
|
void setAvailability (bool ava) { |
|
// on lolin32 lite, led is active LOW |
|
digitalWrite(led, (ava)? LOW : HIGH ); |
|
|
|
#ifdef DFPLAYER |
|
// dfplayer should stay available, set only for lego motor/speed |
|
moteur.setAvailability(ava); |
|
inSpeed.setAvailability(ava); |
|
#else |
|
device.setAvailability (ava); // for whole device |
|
#endif |
|
} |
|
|
|
// setup home-assistant integration |
|
void setupHA(void) { |
|
// HA device configuration |
|
device.setName("Lego Tramway"); |
|
device.setSoftwareVersion("1.0.0"); |
|
device.setModel("88009"); |
|
|
|
#ifndef DFPLAYER |
|
device.enableSharedAvailability(); // configure for whole device |
|
device.enableLastWill(); // for when device unplug |
|
#endif |
|
setAvailability(false); |
|
|
|
// config motor switch |
|
moteur.setIcon("mdi:tram"); |
|
moteur.setName("Moteur"); |
|
moteur.onCommand(onMotorCommand); |
|
// config speed slider |
|
inSpeed.onCommand(onSpeedCommand); |
|
inSpeed.setName("Vitesse"); |
|
inSpeed.setIcon ("mdi:speedometer"); |
|
inSpeed.setMin(-100); |
|
inSpeed.setMax(100); |
|
inSpeed.setStep(5); |
|
inSpeed.setState(speed); |
|
|
|
#ifdef DFPLAYER |
|
// config Button Play |
|
buttonPlay.setIcon("mdi:bell-ring"); |
|
buttonPlay.setName("Play"); |
|
buttonPlay.onCommand(onPlayCommand); |
|
// config volume slider |
|
inVolume.onCommand(onVolumeCommand); |
|
inVolume.setName ("Volume"); |
|
inVolume.setIcon ("mdi:volume-medium"); |
|
inVolume.setMin(0); |
|
inVolume.setMax(30); |
|
inVolume.setState(volume); |
|
#endif |
|
} |
|
|
|
// setup Wifi |
|
void setupWifi(void) { |
|
Serial.println("Connecting to: " + String(ssid)); |
|
|
|
WiFi.begin(ssid, password); |
|
while(WiFi.status() != WL_CONNECTED){ |
|
Serial.print("."); |
|
delay(500); |
|
} |
|
|
|
Serial.println("WiFi connected"); |
|
Serial.print("IP address: "); |
|
Serial.println(WiFi.localIP()); |
|
} |
|
|
|
void setup() { |
|
Serial.begin(115200); |
|
delay(10); |
|
|
|
pinMode(led, OUTPUT); |
|
|
|
setupWifi(); |
|
mqtt.begin(mqtt_broker, mqtt_port); |
|
setupHA(); |
|
|
|
myTrainHub.init(); // initalize the PoweredUpHub instance |
|
|
|
#ifdef DFPLAYER |
|
// for DFAudio |
|
mySoftwareSerial.begin(9600, SERIAL_8N1, 16, 17); // speed, type, RX, TX |
|
Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)")); |
|
if (!myDFPlayer.begin(mySoftwareSerial)) { //Use softwareSerial to communicate with mp3. |
|
Serial.println(myDFPlayer.readType(),HEX); |
|
Serial.println(F("Unable to begin:")); |
|
Serial.println(F("1.Please recheck the connection!")); |
|
Serial.println(F("2.Please insert the SD card!")); |
|
while(true); |
|
} |
|
myDFPlayer.volume(volume); //Set volume value (0~30). |
|
myDFPlayer.outputDevice(DFPLAYER_DEVICE_SD); |
|
myDFPlayer.play(1); //Play the first mp3 |
|
#endif |
|
} |
|
|
|
void loop() { |
|
mqtt.loop(); |
|
|
|
// connect flow. Search for BLE services and try to connect if the uuid of the hub is found |
|
if (myTrainHub.isConnecting()) { |
|
Serial.println("Connecting to HUB..."); |
|
myTrainHub.connectHub(); |
|
if (myTrainHub.isConnected()) { |
|
Serial.println("Connected to HUB"); |
|
Serial.print("Hub address: "); |
|
Serial.println(myTrainHub.getHubAddress().toString().c_str()); |
|
Serial.print("Hub name: "); |
|
Serial.println(myTrainHub.getHubName().c_str()); |
|
|
|
setAvailability(true); |
|
} else { |
|
Serial.println("Failed to connect to HUB"); |
|
setAvailability(false); |
|
} |
|
} |
|
|
|
if (!myTrainHub.isConnected() && !myTrainHub.isConnecting() && ! myTrainHub.isScanning()) { |
|
// setAvailability(false); // seems to make BT connection unreliable, not sure why :( |
|
Serial.println("Reinit BT..."); |
|
myTrainHub.init(); // (re)initalize the PoweredUpHub instance |
|
} |
|
|
|
} |
|
|
ah nevermind, legoino needs the arduino