corneliusmunz / legoino

Arduino Library for controlling Powered UP and Boost controllers
MIT License
259 stars 34 forks source link

Would it be feasable to have an ESP32 behave like an hub? #12

Open AlbanT opened 4 years ago

AlbanT commented 4 years ago

First of all, thanks a lot for this project!!! I have some issue s starting the hub but I'll try to debug that a little further before submitting it as an issue. In the meantime I had this brainwave: Maybe not completely in the scope of this project but I would like to be able to have the Powered Up /Boost App to reconize and connect to an Arduino kind of devices as an hub.... This way it would be possible to use the old power functions and even older motors in conjunction with the app and legoino. So have legoino or the app sent out the command and an microcontroller receives it, just like the hub does, and processes it to whatever it is programmed to do with it...

corneliusmunz commented 4 years ago

@AlbanT That would be a very cool idea. If i find time, i will try it out if it is possible (should be) to be recognized as an hub by the app. I think if you have the right UUID (constant for all powered Up / Boost / Control plus hubs) and send some meaningful firmware version it should be possible. Thanks for that input

marcrupprath commented 4 years ago

I start working doing so with Arduino BLE Most important issue: Advertise manufacturere Data , too. Currently an issue inside the Arduino BLE lib., Never tried with ESP32

Another milestone: Read Sendor data from coneted devices, like Motor. The vasics iff the serial protocoll are documentated by philo here: https://www.philohome.com/wedo2reverse/protocol.htm

I was able to follow init phase with l and XL Motor , but haven't noticed the sequence on how to switsch into data phase.

Any help on how to read sensors with "own" controller (ESP32 or orher) would be helpfull for me to

marcrupprath commented 4 years ago

Hello, due to some issues with ArduinoBLE and Scan Response data i switch to ESP32 as starting point for my HUB Currently i managed to sucessfully connect ESP32 to LEGO Control + and Powered UP APP.

Very basis scetch is as follows: ` / Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp Ported to Arduino ESP32 by Evandro Copercini updates by chegewara /

include

include

include

include

// See the following for generating UUIDs: // https://www.uuidgenerator.net/

define SERVICE_UUID "00001623-1212-EFDE-1623-785FEABCD123"

define CHARACTERISTIC_UUID "00001624-1212-EFDE-1623-785FEABCD123"

BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); BLEAdvertisementData oScanResponseData = BLEAdvertisementData();

const char advLEGO[] = {0x02,0x01,0x06,0x11,0x07,0x23,0xD1,0xBC,0xEA,0x5F,0x78,0x23,0x16,0xDE,0xEF, 0x12,0x12,0x23,0x16,0x00,0x00,0x09,0xFF,0x97,0x03,0x00,0x80,0x06,0x00,0x61,0x00};

const char ArrManufacturerData[8] = {0x97,0x03,0x00,0x80,0x06,0x00,0x41,0x00}; std::string ManufacturerData(ArrManufacturerData ,sizeof(ArrManufacturerData));

const char ArrScanRsponseData[] = {0x05,0x12,0x10,0x00,0x20,0x00,0x02,0x0a,0x00,0x0c,0x09,0x54,0x65,0x63,0x68,0x6e,0x69,0x63,0x20,0x48,0x75,0x62}; std::string ScanResponseData(ArrScanRsponseData ,sizeof(ArrScanRsponseData));

// Set your new MAC Address uint8_t newMACAddress[] = {0x90, 0x84, 0x2B, 0x4A, 0x3A, 0x0A};

void setup() {

Serial.begin(115200); Serial.println("Starting BLE work!");

//esp_base_mac_addr_set(&newMACAddress[0]);

BLEDevice::init("Technic Hub"); BLEServer pServer = BLEDevice::createServer(); BLEService pService = pServer->createService(SERVICE_UUID); BLECharacteristic *pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE );

pCharacteristic->setValue("Hello World says Neil"); pService->start(); // BLEAdvertising pAdvertising = pServer->getAdvertising(); // this still is working for backward compatibility BLEAdvertising pAdvertising = BLEDevice::getAdvertising(); pAdvertising->addServiceUUID(SERVICE_UUID);

pAdvertising->setScanResponse(true);

oAdvertisementData.setShortName("Lego Hub");

//oAdvertisementData.setManufacturerData(ManufacturerData); //oAdvertisementData.addData(advLEGO); //pAdvertising->setAdvertisementData(oAdvertisementData);

oScanResponseData.setManufacturerData(ManufacturerData); oScanResponseData.addData(ScanResponseData);

pAdvertising->setScanResponseData(oScanResponseData);

pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue pAdvertising->setMinPreferred(0x12);

BLEDevice::startAdvertising(); Serial.println("Characteristic defined! Now you can read it in your phone!"); }

void loop() { // put your main code here, to run repeatedly: delay(2000); }`

Once it connects now can be nice starting point to work with to build "virtuel" LEGO Hubs.

corneliusmunz commented 4 years ago

@marcrupprath how cool is that 👍 👏 ! The idea of @AlbanT is working (at least the connection works which is a very good starting point) This enables it to use a custom motor or an old PoweredUp motor. I have to defenitely try that out 😄

marcrupprath commented 4 years ago

The idea can be extended in a wide area of solutions:

My intention was a litle bit different: Because the plugs and sockets for the new otors and sensors are available now, i wan't to use them , too

From my point of view it will be interesting using the several sensors of Motor encoder, color sensor , etc-

You may know: https://www.philohome.com/wedo2reverse/protocol.htm https://github.com/pybricks/technical-info https://github.com/pybricks/technical-info/blob/master/uart-protocol.md

This guy : https://www.eurobricks.com/forum/index.php?/profile/160703-giancann/ has made a very cool simple demonstrator using a color sensor with ESP32 https://youtu.be/3S7GkmqJpic

My Problem is as follows: I am able to read "init phase data" of New XL Motor , but was not able two switch over into data mode. Just a few more informations ;-)

Happy building .

Marc

corneliusmunz commented 4 years ago

@marcrupprath thanks for that input and the informations. I have tested your code and could connect the PoweredUp App on my iPhone to the esp32 controller. Now i will test to read out different commands and maybe integrate your code into the repository. Would this be ok for you?

marcrupprath commented 4 years ago

Would be nice and interesting to follow your progress. Feel free to use my code or own solution ;-) Would be nice if you will share your experience how you handled LEGO sensors and serial proocoll in real project / lib

Right now I just wantedto push and support the idea of Alba a litle bit ;-)

marcrupprath commented 4 years ago

Hi, Had a dicussion about a usefull product idea with Werner (LOK24). About some kind of "Man in the midle" between LEGO Apps and HUB,

My idea is some kind of "Recoder and Player" for powerd up programms --> JSON Projects. As a starting point, why not using a hardware lattform like this:

https://www.hardkernel.com/shop/odroid-go/

or even the M5 Stack with Faces kit as starting point.

1-st Idea: Device is able to connect to powered up Hubs and "Play" selected JSOn Powered Up "Program" from SD Card.
This can be achived by using your legoino lib.

2-nd: Idea Device can connect to powered up app and "record" command stream send and stores it on sd card for later use,

What do you think about it ?

GianCann commented 4 years ago

This is my starting point: https://github.com/GianCann/ATS/blob/master/ESP32_LEGO/PUPHubEmulator.ino

Video: https://youtu.be/vdZUJM3Gj-o

corneliusmunz commented 4 years ago

@GianCann Very good starting point and i have used your code to build a first draft of a legoino version of your code where you can emulate a hub. I have tried to connect with that idea a "old" powerfunction train motor with the powered up hub. With the Atom M5 it is possible to directly use the IR LED on the board to send out power function commands. I have pushed the changes on the following feature branch: https://github.com/corneliusmunz/legoino/tree/feature/add_hub_emulation Maybe you can have a look on that :-) I hightly appreciate your feedback! I have made a short video: https://www.youtube.com/watch?v=RTNexxT4-yQ

corneliusmunz commented 4 years ago

First Beta implementation as part of the 1.0.0 release: https://github.com/corneliusmunz/legoino/releases/tag/1.0.0

wmarkow commented 3 years ago

Hi. I will definitelly try your hub emulator with ESP and some - let's say - custom train.

My kids already have one Lego set but it would be nice to have more :) I bought in Lidl a cheap (for 30 EUR) "lego compatible" train from Playtive - what is good that the tracks match to original Lego so I can join it together. In this price I have 3.2m of tracks (including one railroad switch), around 750 lego compatible bricks, motor with receiver and a remote controller. However remote controller is not lego compatible; probably it doesn't even use BLE (my Android phone doesn't see it in nearby). The remote control doesn't work so nice and smooth as original Lego; I have the feeling that the train goes to fast.

I just want to rework it and put ESP32 inside with hub emulator so I can control it from Android app. Currently I'm using PoweredUp. Is there any other application available? What do you use? I would like to control those two trains togehter at the same time. I'm not quite sure if this is possible with PoweredUp. Please advice.

I have also an idea to build a railway turntable (somewhere in the future), with ESP32 but I'm not sure at the moment if that will work with PoweredUp (or any other similar application).

wmarkow commented 3 years ago

I tried this solution but it doesn't work in my environment. I'm using

Hm, I have also BLE Scanner application installed and it connects correctly, see the log from ESP32 after connection:

16:41:04.000 -> [D][Lpf2HubEmulation.cpp:30] onConnect(): Device connected
16:41:05.000 -> [D][Lpf2HubEmulation.cpp:301] writeValue(): write message (15): ⸮_⸮?
16:41:06.000 -> [D][Lpf2HubEmulation.cpp:301] writeValue(): write message (15): ⸮_⸮?
16:41:07.000 -> [D][Lpf2HubEmulation.cpp:301] writeValue(): write message (15): ⸮_⸮?

Please advice how to find out what is going on. Does it have GATT server under the hood?

wmarkow commented 3 years ago

Ok, I think I know what is going on. I have implemented also a small Android application to connect to Gatt server. This application also doesn't want to connect (I have 133 status response when connecting to Gatt server). After a while of googling I have found this isse on github and this specific answer helped me to fix the problem: https://github.com/android/connectivity-samples/issues/18#issuecomment-374600798

So far so good but I needed to rise the API level from 21 to 23 in my test app. However Powered Up still doesn't connect. Maybe something can be changed on the Legoino side to make it working with Powered Up and Android >= 6?

I have Huawei SNE-LX1 with Android 10.

wmarkow commented 3 years ago

It also doesn't work with my Samsung device with Android 5.1.1: the same error. Even BLE Scanner doesn't want to work.

What is good: my Android app and also BLE Scanner both work with the example code from @marcrupprath

Update: this issue may be related to NimBLE-Arduino library itself, see https://github.com/h2zero/NimBLE-Arduino/issues/129

marcrupprath commented 3 years ago

After my first test, Giancarlo and me had an intense discussion, about : what is missing, best practices .... In the end i think the step by step guidance he wrote in the "eurobricks" forum. Is a good guidline to follow, i think.

Because the first example i posted here is for simple "does it connect ?" Only. You should take a look on the extended code Giancarlo posted here ?

Backround is: My fist example here does not include some statements, mandantory to activate "Notification" services ;-) I added this later. You have to keep that in mind.

wmarkow commented 3 years ago

@marcrupprath I have found it in the meantime. I think it is related to the NimBLE-Arduino library; please see the issue from my last comment.

To make it working I needed to add a

void onConnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
    /** We can use the connection handle here to ask for different connection parameters.
     *  Args: connection handle, min connection interval, max connection interval
     *  latency, supervision timeout.
     *  Units; Min/Max Intervals: 1.25 millisecond increments.
     *  Latency: number of intervals allowed to skip.
     *  Timeout: 10 millisecond increments, try for 5x interval time for best results.  
     */
    // wmarkow: without the line below the "BLE Scanner" Android app doesn't want to connect to this server
    pServer->updateConnParams(desc->conn_handle, 24, 48, 0, 60);
  };

method in Lpf2HubServerCallbacks inside of Legoino library. WIth this change the BLE Scanner application connects correctly to the emulated Lego hub. In my custom Android app I needed to make some tweaks to connect correctly (see the raleted NimBLE-Arduino library issue mentioned in my revious comment).

Unfortunatelly Powered Up still doesn't connect to the emulated hub. I hope that something can be improved in Legoino or NimBLE-Arduino to make it working with Powered UP on my devices. It may be also related only to some specific Android devices and only on some specific Android versions. I do not know - I'm not so familiar with BLE.

For now I'm giving up with Powered UP and will use my own custom Android application to control the trains. Now I can continue the fun with my not-lego-train and put inside an ESP32 with a motor driver and some battery.

One more thing: @marcrupprath - your initial code uses a "native" ESP32 library for BLE, is that correct? Legoino uses NimBLE-Arduino.

AlbanT commented 3 years ago

@wmarkow I havn't read your previous posts in detail but I would like to point out that I have had issues with the app recognizing the ESP32 on an Android device. On my Apple it works without any issues. On my sons Android I need to disable Bluetooth and completely close the app. Then start Bluetooth and do a scan for devices. Just a scan not connecting. After I restart the app the ESP is recognized. Without the scan it doesn't work for me.

corneliusmunz commented 3 years ago

Hi @wmarkow : Sorry for the late reply on your comments but i was a littlebit busy ;-) For android we faced some issues with the connection procedure. The connection problem was described in the following issue: https://github.com/corneliusmunz/legoino/issues/27 The solution is to kill the app and disable the bluetooth radio on the android device completly (as described by @AlbanT already) this helps to connect to android devices. I think this will appear only if the android device has a connection bevore to a "real" Lego hub. Then the app does maybe some caching.

I am currently working on the support of other devices (hubs, motor and sensors) for the hub emulation.

The onConnect callback is already implemented in the Lpf2HubEmulation.cpp class and if the app ask for different device possibilites on connected ports (mode options e.g.) the emulation answers with the appropriate commands. @wmarkow Thanks for figuring out the different connectionParameters for the NimBLE lib. I will try that out. Unfortunately on the two android devices which i have tested i could not reproduce your issues :-(

@marcrupprath I was following your and Giancanns examples to implement the emulation class and did the notification steps additionally.

wmarkow commented 3 years ago

Thanks for the hints:

On my sons Android I need to disable Bluetooth and completely close the app. Then start Bluetooth and do a scan for devices. Just a scan not connecting. After I restart the app the ESP is recognized.

This also works fine for me, after this steps Powered Up (on Huawei phone with Android 10) connects correctly to Legoino emulated hub. Then I did one more test: I disconnected device, switched bluetooth off, switched of Powered Up, cleared Powered Up application cache, start Powered Up again (it was downlaoding something from the Internet), switched on bluetooth and connect to a real Lego train. So far so good. Then I disconnected from Lego train and tried to connect to Legoino emulate hub: no connection. To connecte again to Legoino hub I needed to do again: switch off bluetooth, close Powered Up and clar its cache, switch bluetooth on, go to bluetooth settings and wait until Legoino hub appears on the list, open Powered Up and the device connects easily. Really weird.

Another quick question: can Powered Up controll two trains simultanously?

corneliusmunz commented 3 years ago

@wmarkow Thanks that you have tried it out and tried different sequences! I will have a look if it is helpful if I randomly use different device ids. Regarding your question about controlling different hubs at the same time: that's definitely possible. You can connect to up to 9 hubs at the same time but you have to increase the following constant in the nimconfig.h to the Max number of connections you want to use: '#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3' After that you have to restart the Arduino IDE to force the recompiling of the NimBLE-Arduino library

wmarkow commented 3 years ago

@corneliusmunz thanks for your reply. In the meantime I spent some time on the Android problem. By experiments I managed to make it working, however not everything is still clear to me. I have commented in the #27, because there is a better place for it.