Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. My Project
  3. Mysensorized Roomba

Mysensorized Roomba

Scheduled Pinned Locked Moved My Project
18 Posts 9 Posters 8.5k Views 10 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Eawo

    Maybe this is off topic but I'm going to buy a roomba but it is so many versions. Will roomba 615 or 616 do the job or is the newer versions smarter cleaner? I have around 80kvd

    parachutesjP Offline
    parachutesjP Offline
    parachutesj
    wrote on last edited by
    #9

    @Eawo I do have a 581 and not 100% sure what has been changed on newer models. Maybe you ask in a roomba forum

    parachutesjP 1 Reply Last reply
    0
    • parachutesjP parachutesj

      @Eawo I do have a 581 and not 100% sure what has been changed on newer models. Maybe you ask in a roomba forum

      parachutesjP Offline
      parachutesjP Offline
      parachutesj
      wrote on last edited by
      #10

      All,
      I did some updates also thanks to @Eoreh I updated my code a bit. Anyhow, no really news on software side but was able to fit it more or less completely inside of the Roomba.

      1. I wanted to fit all inside and I think there is enough space but wanted to be able to disable it and thought about a dip-switch somewhere but then decided to have it connected via DIN as before. Means also no soldering on Roomba

      2. finding a spot was easy:
        alt text
        There is enough space on the side of the bin. (In picture, the external charging port was already removed)

      3. I soldered all together and decided to opt for a Nano instead of a Pro Mini due to the lack of 3.3V on board. I know radio might be better powered with a voltage regulator but the reception and reliability is not too important here. Anyhow not experienced any issues so far. I also used the SMD radio to save some extra space.
        The voltage regulator has a heat sink mounted which is pointing where the charing port was and is getting some "fresh air" ;-)
        alt text

      4. all in place and ready to be closed again
        alt text

      5. closed without top plate
        alt text

      If it stops working or needs a reset, I only need to unplug and replug

      M 1 Reply Last reply
      0
      • parachutesjP parachutesj

        All,
        I did some updates also thanks to @Eoreh I updated my code a bit. Anyhow, no really news on software side but was able to fit it more or less completely inside of the Roomba.

        1. I wanted to fit all inside and I think there is enough space but wanted to be able to disable it and thought about a dip-switch somewhere but then decided to have it connected via DIN as before. Means also no soldering on Roomba

        2. finding a spot was easy:
          alt text
          There is enough space on the side of the bin. (In picture, the external charging port was already removed)

        3. I soldered all together and decided to opt for a Nano instead of a Pro Mini due to the lack of 3.3V on board. I know radio might be better powered with a voltage regulator but the reception and reliability is not too important here. Anyhow not experienced any issues so far. I also used the SMD radio to save some extra space.
          The voltage regulator has a heat sink mounted which is pointing where the charing port was and is getting some "fresh air" ;-)
          alt text

        4. all in place and ready to be closed again
          alt text

        5. closed without top plate
          alt text

        If it stops working or needs a reset, I only need to unplug and replug

        M Offline
        M Offline
        moskovskiy82
        wrote on last edited by moskovskiy82
        #11

        @parachutesj Mind posting your finished code?

        Also wonder what is the correct MQTT payload to start for example cleaning?

        Upon start i see the following

        mys-out/15/255/3/0/11 MYS Roomba
        mys-out/15/255/3/0/12 2.1
        mys-out/15/0/0/0/3 Roomba-Stop
        mys-out/15/1/0/0/3 Roomba-Dock
        mys-out/15/2/0/0/3 Roomba-Clean
        mys-out/15/3/0/0/3 Roomba-Spot
        mys-out/15/4/0/0/3 Roomba-Max
        mys-out/15/5/0/0/3 Roomba-Power
        mys-out/15/6/0/0/3 Roomba-Play
        mys-out/15/100/0/0/6 Roomba-Batt-Temp
        mys-out/15/101/0/0/39 Roomba-Batt-Proc
        mys-out/15/102/0/0/30 Roomba-Batt-Volt
        mys-out/15/103/0/0/30 Roomba-Batt-mAH
        mys-out/15/104/0/0/36 Roomba-Batt-CHt
        mys-out/15/105/0/0/36 Roomba-Batt-CHs

        But publishing to

        mys-in/15/2/1/0/3
        mys-in/15/2/1/0/2

        with payload 1 doesn't do anything

        parachutesjP 1 Reply Last reply
        0
        • M moskovskiy82

          @parachutesj Mind posting your finished code?

          Also wonder what is the correct MQTT payload to start for example cleaning?

          Upon start i see the following

          mys-out/15/255/3/0/11 MYS Roomba
          mys-out/15/255/3/0/12 2.1
          mys-out/15/0/0/0/3 Roomba-Stop
          mys-out/15/1/0/0/3 Roomba-Dock
          mys-out/15/2/0/0/3 Roomba-Clean
          mys-out/15/3/0/0/3 Roomba-Spot
          mys-out/15/4/0/0/3 Roomba-Max
          mys-out/15/5/0/0/3 Roomba-Power
          mys-out/15/6/0/0/3 Roomba-Play
          mys-out/15/100/0/0/6 Roomba-Batt-Temp
          mys-out/15/101/0/0/39 Roomba-Batt-Proc
          mys-out/15/102/0/0/30 Roomba-Batt-Volt
          mys-out/15/103/0/0/30 Roomba-Batt-mAH
          mys-out/15/104/0/0/36 Roomba-Batt-CHt
          mys-out/15/105/0/0/36 Roomba-Batt-CHs

          But publishing to

          mys-in/15/2/1/0/3
          mys-in/15/2/1/0/2

          with payload 1 doesn't do anything

          parachutesjP Offline
          parachutesjP Offline
          parachutesj
          wrote on last edited by
          #12

          @moskovskiy82 I did not change too much compared to @EmielA on the code. worked pretty good until I bought a new roomba recently. Haven't tried it on the 980 yet:

          // Enable debug prints to serial monitor
          #define MY_DEBUG
          
          // Enable and select radio type attached
          #define MY_RADIO_NRF24
          //#define MY_RADIO_RFM69
          
          // Enable repeater functionality for this node
          #define MY_REPEATER_FEATURE
          
          #define CHILD_ID_BATT_TEMP          100  // Id of the 2nd msg1_3
          #define CHILD_ID_BATT_PROC          101   // Id of the 2nd msg1_4
          #define CHILD_ID_BATT_VOLT          102   // Id of the 2nd msg1_2
          #define CHILD_ID_BATT_AH            103   // Id of the 2nd msg2_5
          #define CHILD_ID_BATT_CHARGE_TYPE   104   // Id of the 2nd msg1_1
          #define CHILD_ID_BATT_CHARGE_SOURCE 105   // Id of the 2nd msg2_2
          
          
          #include <MySensors.h>
          #include <SoftwareSerial.h>
          
          //#define RELAY_1  5  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
          //#define NUMBER_OF_RELAYS 2 // Total number of attached relays
          //#define RELAY_ON 1  // GPIO value to write to turn on attached relay
          //#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
          
          #define NUMBER_OF_FUNCTION 7 
          #define NUMBER_OF_SENSORS 6
          #define ROOMBA_READ_TIMEOUT 300
          #define ROOMBA_WAKE_COUNT 10
          int ddPin = 6;
          
          int rxPin = 3;
          int txPin = 4;
          int ledPin = 13;
          
          SoftwareSerial roomba(rxPin, txPin);
          
          const char SWITCH_NAMES[NUMBER_OF_FUNCTION][14] = { "Roomba-Stop","Roomba-Dock","Roomba-Clean","Roomba-Spot","Roomba-Max","Roomba-Power","Roomba-Play" };
          const char SENSORS_NAMES[NUMBER_OF_SENSORS][24] = { "Roomba-Batt-Temp","Roomba-Batt-Proc","Roomba-Batt-Volt", "Roomba-Batt-mAH" , "Roomba-Batt-CHt" , "Roomba-Batt-CHs" };
          
          
          uint8_t buf[52];
          boolean lowBattery = true; // Acts as a debounce
          long battery_Current_mAh = 0;
          long battery_Total_mAh = 0;
          long battery_percent = 0;
          boolean DeadBattery = false;
          boolean FullBattery = true;
          unsigned long chargingState = 0;
          long voltage = 0;
          long temp = 0;
          long OiMode = 0;
          long ChargeSource = 0;
          
          long sensorfrequency = 300000; // 300000 = 5 min - frequency the sensors are read
          long lastsensorread = 0; // when were the sensors read the last time
          unsigned long lastsensorssend = 0;
          
          const char ChargeTypes[6][34] = { "Not charging","Reconditioning Charging","Full Charging","Trickle Charging","Waiting","Charging Fault Condition" };
          const char OiTypes[4][14] = { "Off","Passive","Safe","Full" };
          
          int packetSizes[58] = {
              0,0,0,0,0,0, //1-6
              1,1,1,1,1,1,1,1,1,1,1,1, //7-18
              2,2, //19-20
              1, //21
              2,2, //22-23
              1, //24
              2,2,2,2,2,2,2, //25-31
              1, //32
              2, //33
              1,1,1,1,1, //34-38
              2,2,2,2,2,2, //39-44
              1, //45
              2,2,2,2,2,2, //46-51
              1,1, //52-53
              2,2,2,2, //54-57
              1 //58
          };
          #define bumpright (sensorbytes[0] & 0x01)
          #define bumpleft  (sensorbytes[0] & 0x02)
          
          
          MyMessage msg1_3(CHILD_ID_BATT_TEMP, V_TEMP); //status of Temperature
          MyMessage msg1_4(CHILD_ID_BATT_PROC, V_PH); //status of Charge [%]
          MyMessage msg1_2(CHILD_ID_BATT_VOLT, V_VOLTAGE); //status of Voltage
          MyMessage msg2_5(CHILD_ID_BATT_AH, V_CURRENT); //status of mAH
          MyMessage msg1_1(CHILD_ID_BATT_CHARGE_TYPE, V_TEXT); //status of charget type
          MyMessage msg2_2(CHILD_ID_BATT_CHARGE_SOURCE, V_TEXT); //status of charger source
          
          void setup() {
              pinMode(ddPin, OUTPUT);
              digitalWrite(ddPin, LOW);
              Serial.begin(115200);
              while (!Serial) {
                  ; // wait for serial port to connect. Needed for native USB port only
              }
              roomba.begin(115200);
              //Serial.println("Sending start command...");
              //delay(1000);
              //// set up ROI to receive commands
              defsongs();
              delay(500);
              rstop();
              Serial.println("Ready to go!");
          }
          
          void presentation()
          {
              // Send the sketch version information to the gateway and Controller
              sendSketchInfo("Roomba", "1.2");
          
              for (int sensor = 0; sensor < NUMBER_OF_FUNCTION; sensor++) {
                  // Register all sensors to gw (they will be created as child devices)
                  present(sensor, S_BINARY, SWITCH_NAMES[sensor]);
                  delay(100);
              }
              present(CHILD_ID_BATT_TEMP, S_TEMP, SENSORS_NAMES[0]); delay(100);
              present(CHILD_ID_BATT_PROC, S_WATER_QUALITY, SENSORS_NAMES[1]); delay(100);
              present(CHILD_ID_BATT_VOLT, S_MULTIMETER, SENSORS_NAMES[2]);    delay(100);
              present(CHILD_ID_BATT_AH, S_MULTIMETER, SENSORS_NAMES[3]);  delay(100);
              present(CHILD_ID_BATT_CHARGE_TYPE, S_INFO, SENSORS_NAMES[4]); delay(100);
              present(CHILD_ID_BATT_CHARGE_SOURCE, S_INFO, SENSORS_NAMES[5]); delay(100);
          }
          
          void loop() {
              unsigned long now = millis();
              if (now > lastsensorssend + sensorfrequency)
              {
                  readsensors();
                  lastsensorssend = now;
              }
          }
          
          
          void receive(const MyMessage &message) {
            // We only expect one type of message from controller. But we better check anyway.
            if (message.type == V_LIGHT) {
              int mySensor = message.sensor;
              int myComand = message.getBool();
          
              //Serial.print(message.sensor-1+RELAY_1);
          
              if (mySensor == 0) {
                if (myComand == 1) {
                  Serial.println("Clean");
                  //clean();
                  rcommand(135);
                }
                else {
                  Serial.println("Stopp1");
                  //halt();
                  rstop();
                }
              }
          
              if (mySensor == 1) {
                if (myComand == 1) {
                  Serial.println("dock");
                  //dock();
                  rcommand(143);
                }
                else {
                  Serial.println("Stopp2");
                  //halt();
                  rstop();
                }
              }
              if (mySensor == 2) {
                if (myComand == 1) {
                  Serial.println("song");
                  //dock();
                  rcommand(141);
                  rsong(0);
                }
                else {
                  Serial.println("Stopp2");
                  //halt();
                  rstop();
                }
              }
          
            }
          }
          
          void halt() {
            ;
            roomba.write(131);  // SAFE
            byte j = 0x00;
            roomba.write(137);
            roomba.write(j);
            roomba.write(j);
            roomba.write(j);
            roomba.write(j);
          }
          
          void dock() {
            delay(1000);
            roomba.write(143);
          }
          
          void clean() {
            delay(1000);
            roomba.write(135);
          }
          
          void rstop() {
              if (rwakeup()) {
                  roomba.write(128);  delay(100);
                  roomba.write(131);  delay(100);
                  roomba.write(137);  delay(100);
                  byte j = 0x00;
                  roomba.write(j); delay(100);
                  roomba.write(j); delay(100);
                  roomba.write(j); delay(100);
                  roomba.write(j); delay(100);
                  roomba.write(128);
              }
          
          }
          
          void rsong(int b) {
              roomba.write(b); delay(100);
          }
          
          
          
          void rcommand(int command) {
              if (rwakeup()) {
                  roomba.write(128);  delay(100);
                  roomba.write(131);  delay(100);
                  roomba.write(command);
              }
          }
          
          void play(char note, int rlong) {
              roomba.write(rnote(note));  delay(10);  roomba.write(64 / rlong);   delay(10);
          }
          
          
          bool rwakeup() {
              bool ret = getSensors(6, buf, 52);
              Serial.print("wakeup: ");
              Serial.print(ret);
              if (!ret) {
                  for (int ii = 1; ii < ROOMBA_WAKE_COUNT; ii++)
                  {
                      for (int jj = 0; jj < 3; jj++) {
                          digitalWrite(ddPin, HIGH); delay(10); 
                          digitalWrite(ddPin, LOW); delay(2);
                      }
                      delay(100);
                      roomba.write(128);
                      if (getSensors(6, buf, 52)) {
                          ret = true;
                          break;
                      }
                      Serial.print("-");
                  }
              }
              Serial.println(ret);
              return ret;
          }
          
          bool getSensors(uint8_t packetID, uint8_t* dest, uint8_t len) {
              roomba.write(142);
              delay(100);
              roomba.write(packetID);
              delay(100);
              return getData(dest, len);
          }
          
          
          bool getData(uint8_t* dest, uint8_t len)
          {
              while (len-- > 0)
              {
                  unsigned long startTime = millis();
                  while (!roomba.available())
                  {
                      // Look for a timeout
                      if (millis() > startTime + ROOMBA_READ_TIMEOUT)
                          return false; // Timed out
                  }
                  *dest++ = roomba.read();
              }
              return true;
          }
          
          //for sensorgetting
          int getPacketSize(int p) {
              return packetSizes[p - 1];
          }
          int getPacketOffset(int p) {
              int i = 0;
              for (int s = 1; s < p; s++) {
                  i += getPacketSize(s);
              }
              return i;
          }
          
          //read sensors
          void readsensors()
          {
          
              if (getSensors(6, buf, 52)) {
          
                  int off = 0;
          
                  // Battery Checks
                  off = getPacketOffset(21);
                  chargingState = buf[off + 0];
                  voltage = buf[off + 2] + 256 * buf[off + 1];
                  temp = buf[off + 5];
                  battery_Current_mAh = buf[off + 7] + 256 * buf[off + 6];
                  battery_Total_mAh = buf[off + 9] + 256 * buf[off + 8];
          
                  if (battery_Total_mAh == 0) battery_Total_mAh = 1;
                  int nBatPcent = battery_Current_mAh * 100 / battery_Total_mAh;
                  battery_percent = nBatPcent;
          
                  //Oi Mode
                  off = getPacketOffset(35);
                  OiMode = buf[off + 0];
          
                  //ChargeSource
                  off = getPacketOffset(34);
                  ChargeSource = buf[off + 0];
          
          
                  send(msg1_3.set(temp));  delay(100);
                  send(msg1_4.set(battery_percent));  delay(100);
                  send(msg1_2.set(round(voltage / 10), 1));  delay(100);
                  send(msg2_5.set(battery_Current_mAh));  delay(100);
                  send(msg1_1.set(ChargeTypes[chargingState]));  delay(100);
                  send(msg2_2.set(ChargeSource));  delay(100);
          
                  //send(msg2_5.set(chargingState));  // Send info value to gw
                  //send(msg2_5.set("charging state"));  // Send info value to gw
                  //send(msg2_5.set(battery_Total_mAh));  // Send info value to gw
                  //send(msg2_1.set(OiTypes[OiMode]));  // Send info value to gw
                  lastsensorread = millis();
          
              }
              else { send(msg1_1.set("roomba is off")); }  // Send info value to gw
          }
          
          void defsongs() {
              uint8_t zero = 0;
              roomba.write(128);  delay(100); roomba.write(131);  delay(100); //[128 131](Start the command stream and change roomba mode to "Safe" mode)
              roomba.write(140);  delay(100); roomba.write(zero); delay(100); //[140 0](Start song definition and define the first song, song number 0)
              roomba.write(25);   //[16](16 notes will be sent for song number 0)
              play('E', 4);       //[76 16](play Mi sound for 1 / 4 seconds) // E
              play('E', 4);
              play('E', 2);
              play('E', 4);
              play('E', 4);
              play('E', 2);       //[76 32](play Mi sound for 1 / 2 seconds)
              play('E', 4);
              play('G', 4);
              play('C', 4);
              play('D', 4);
              play('E', 1);
          
              play('F', 4);
              play('F', 4);
              play('F', 2);
          
              play('F', 4);
              play('E', 4);
              play('E', 2);
          
              play('E', 4);
              play('D', 4);
              play('D', 4);
              play('E', 4);
              play('D', 1);
              delay(100);
              roomba.write(128);
          }
          
          int rnote(char note) {
              int command = 31;
              switch (note) {
              case 'C': command = 72; break;
              case 'D': command = 74; break;
              case 'E': command = 76; break;
              case 'F': command = 77; break;
              case 'G': command = 79; break;
              }
              return command;
          }
          
          
          Z 1 Reply Last reply
          0
          • gohanG Offline
            gohanG Offline
            gohan
            Mod
            wrote on last edited by gohan
            #13

            Just a question, but wouldn't it be an esp8266 a more compact solution? (Not to mention the quick ota programming) Or the roomba is running 5v serial output?

            parachutesjP 1 Reply Last reply
            0
            • gohanG gohan

              Just a question, but wouldn't it be an esp8266 a more compact solution? (Not to mention the quick ota programming) Or the roomba is running 5v serial output?

              parachutesjP Offline
              parachutesjP Offline
              parachutesj
              wrote on last edited by
              #14

              @gohan ESP is probably a good alternative. but then again you could also buy an after market wireless module for your roomba.
              I am not sure about the serial output, but I think it is 5v.

              but there is plenty of space for a nano or pro mini. wemos mini or nodemcu should also fit

              1 Reply Last reply
              0
              • M Offline
                M Offline
                moskovskiy82
                wrote on last edited by
                #15

                ESP is the best solution although couldn't find the code with sensors (only clean/dock commands). I recently made a post on HomeAssistant forum - how wemos D1 fits nicely inside. You only need a buck converter and 4 cat5 wires soldered. And 5V serial output is not such a big problem as you need a voltage divider only on rx pin (didn't put it)

                P.S. But then one of those "machine revolt weeks happened" so my esproomba didn't respond and then i burned it down. Next day my RPi3 went down with HA and lots of goodies. And today ESXi...

                1 Reply Last reply
                0
                • gohanG Offline
                  gohanG Offline
                  gohan
                  Mod
                  wrote on last edited by gohan
                  #16

                  Oh man, that sucks a lot. Best luck for your disaster recovery

                  PS if everything you are touching is failing, be careful when you are going to pee 😂

                  1 Reply Last reply
                  1
                  • parachutesjP parachutesj

                    @moskovskiy82 I did not change too much compared to @EmielA on the code. worked pretty good until I bought a new roomba recently. Haven't tried it on the 980 yet:

                    // Enable debug prints to serial monitor
                    #define MY_DEBUG
                    
                    // Enable and select radio type attached
                    #define MY_RADIO_NRF24
                    //#define MY_RADIO_RFM69
                    
                    // Enable repeater functionality for this node
                    #define MY_REPEATER_FEATURE
                    
                    #define CHILD_ID_BATT_TEMP          100  // Id of the 2nd msg1_3
                    #define CHILD_ID_BATT_PROC          101   // Id of the 2nd msg1_4
                    #define CHILD_ID_BATT_VOLT          102   // Id of the 2nd msg1_2
                    #define CHILD_ID_BATT_AH            103   // Id of the 2nd msg2_5
                    #define CHILD_ID_BATT_CHARGE_TYPE   104   // Id of the 2nd msg1_1
                    #define CHILD_ID_BATT_CHARGE_SOURCE 105   // Id of the 2nd msg2_2
                    
                    
                    #include <MySensors.h>
                    #include <SoftwareSerial.h>
                    
                    //#define RELAY_1  5  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
                    //#define NUMBER_OF_RELAYS 2 // Total number of attached relays
                    //#define RELAY_ON 1  // GPIO value to write to turn on attached relay
                    //#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
                    
                    #define NUMBER_OF_FUNCTION 7 
                    #define NUMBER_OF_SENSORS 6
                    #define ROOMBA_READ_TIMEOUT 300
                    #define ROOMBA_WAKE_COUNT 10
                    int ddPin = 6;
                    
                    int rxPin = 3;
                    int txPin = 4;
                    int ledPin = 13;
                    
                    SoftwareSerial roomba(rxPin, txPin);
                    
                    const char SWITCH_NAMES[NUMBER_OF_FUNCTION][14] = { "Roomba-Stop","Roomba-Dock","Roomba-Clean","Roomba-Spot","Roomba-Max","Roomba-Power","Roomba-Play" };
                    const char SENSORS_NAMES[NUMBER_OF_SENSORS][24] = { "Roomba-Batt-Temp","Roomba-Batt-Proc","Roomba-Batt-Volt", "Roomba-Batt-mAH" , "Roomba-Batt-CHt" , "Roomba-Batt-CHs" };
                    
                    
                    uint8_t buf[52];
                    boolean lowBattery = true; // Acts as a debounce
                    long battery_Current_mAh = 0;
                    long battery_Total_mAh = 0;
                    long battery_percent = 0;
                    boolean DeadBattery = false;
                    boolean FullBattery = true;
                    unsigned long chargingState = 0;
                    long voltage = 0;
                    long temp = 0;
                    long OiMode = 0;
                    long ChargeSource = 0;
                    
                    long sensorfrequency = 300000; // 300000 = 5 min - frequency the sensors are read
                    long lastsensorread = 0; // when were the sensors read the last time
                    unsigned long lastsensorssend = 0;
                    
                    const char ChargeTypes[6][34] = { "Not charging","Reconditioning Charging","Full Charging","Trickle Charging","Waiting","Charging Fault Condition" };
                    const char OiTypes[4][14] = { "Off","Passive","Safe","Full" };
                    
                    int packetSizes[58] = {
                        0,0,0,0,0,0, //1-6
                        1,1,1,1,1,1,1,1,1,1,1,1, //7-18
                        2,2, //19-20
                        1, //21
                        2,2, //22-23
                        1, //24
                        2,2,2,2,2,2,2, //25-31
                        1, //32
                        2, //33
                        1,1,1,1,1, //34-38
                        2,2,2,2,2,2, //39-44
                        1, //45
                        2,2,2,2,2,2, //46-51
                        1,1, //52-53
                        2,2,2,2, //54-57
                        1 //58
                    };
                    #define bumpright (sensorbytes[0] & 0x01)
                    #define bumpleft  (sensorbytes[0] & 0x02)
                    
                    
                    MyMessage msg1_3(CHILD_ID_BATT_TEMP, V_TEMP); //status of Temperature
                    MyMessage msg1_4(CHILD_ID_BATT_PROC, V_PH); //status of Charge [%]
                    MyMessage msg1_2(CHILD_ID_BATT_VOLT, V_VOLTAGE); //status of Voltage
                    MyMessage msg2_5(CHILD_ID_BATT_AH, V_CURRENT); //status of mAH
                    MyMessage msg1_1(CHILD_ID_BATT_CHARGE_TYPE, V_TEXT); //status of charget type
                    MyMessage msg2_2(CHILD_ID_BATT_CHARGE_SOURCE, V_TEXT); //status of charger source
                    
                    void setup() {
                        pinMode(ddPin, OUTPUT);
                        digitalWrite(ddPin, LOW);
                        Serial.begin(115200);
                        while (!Serial) {
                            ; // wait for serial port to connect. Needed for native USB port only
                        }
                        roomba.begin(115200);
                        //Serial.println("Sending start command...");
                        //delay(1000);
                        //// set up ROI to receive commands
                        defsongs();
                        delay(500);
                        rstop();
                        Serial.println("Ready to go!");
                    }
                    
                    void presentation()
                    {
                        // Send the sketch version information to the gateway and Controller
                        sendSketchInfo("Roomba", "1.2");
                    
                        for (int sensor = 0; sensor < NUMBER_OF_FUNCTION; sensor++) {
                            // Register all sensors to gw (they will be created as child devices)
                            present(sensor, S_BINARY, SWITCH_NAMES[sensor]);
                            delay(100);
                        }
                        present(CHILD_ID_BATT_TEMP, S_TEMP, SENSORS_NAMES[0]); delay(100);
                        present(CHILD_ID_BATT_PROC, S_WATER_QUALITY, SENSORS_NAMES[1]); delay(100);
                        present(CHILD_ID_BATT_VOLT, S_MULTIMETER, SENSORS_NAMES[2]);    delay(100);
                        present(CHILD_ID_BATT_AH, S_MULTIMETER, SENSORS_NAMES[3]);  delay(100);
                        present(CHILD_ID_BATT_CHARGE_TYPE, S_INFO, SENSORS_NAMES[4]); delay(100);
                        present(CHILD_ID_BATT_CHARGE_SOURCE, S_INFO, SENSORS_NAMES[5]); delay(100);
                    }
                    
                    void loop() {
                        unsigned long now = millis();
                        if (now > lastsensorssend + sensorfrequency)
                        {
                            readsensors();
                            lastsensorssend = now;
                        }
                    }
                    
                    
                    void receive(const MyMessage &message) {
                      // We only expect one type of message from controller. But we better check anyway.
                      if (message.type == V_LIGHT) {
                        int mySensor = message.sensor;
                        int myComand = message.getBool();
                    
                        //Serial.print(message.sensor-1+RELAY_1);
                    
                        if (mySensor == 0) {
                          if (myComand == 1) {
                            Serial.println("Clean");
                            //clean();
                            rcommand(135);
                          }
                          else {
                            Serial.println("Stopp1");
                            //halt();
                            rstop();
                          }
                        }
                    
                        if (mySensor == 1) {
                          if (myComand == 1) {
                            Serial.println("dock");
                            //dock();
                            rcommand(143);
                          }
                          else {
                            Serial.println("Stopp2");
                            //halt();
                            rstop();
                          }
                        }
                        if (mySensor == 2) {
                          if (myComand == 1) {
                            Serial.println("song");
                            //dock();
                            rcommand(141);
                            rsong(0);
                          }
                          else {
                            Serial.println("Stopp2");
                            //halt();
                            rstop();
                          }
                        }
                    
                      }
                    }
                    
                    void halt() {
                      ;
                      roomba.write(131);  // SAFE
                      byte j = 0x00;
                      roomba.write(137);
                      roomba.write(j);
                      roomba.write(j);
                      roomba.write(j);
                      roomba.write(j);
                    }
                    
                    void dock() {
                      delay(1000);
                      roomba.write(143);
                    }
                    
                    void clean() {
                      delay(1000);
                      roomba.write(135);
                    }
                    
                    void rstop() {
                        if (rwakeup()) {
                            roomba.write(128);  delay(100);
                            roomba.write(131);  delay(100);
                            roomba.write(137);  delay(100);
                            byte j = 0x00;
                            roomba.write(j); delay(100);
                            roomba.write(j); delay(100);
                            roomba.write(j); delay(100);
                            roomba.write(j); delay(100);
                            roomba.write(128);
                        }
                    
                    }
                    
                    void rsong(int b) {
                        roomba.write(b); delay(100);
                    }
                    
                    
                    
                    void rcommand(int command) {
                        if (rwakeup()) {
                            roomba.write(128);  delay(100);
                            roomba.write(131);  delay(100);
                            roomba.write(command);
                        }
                    }
                    
                    void play(char note, int rlong) {
                        roomba.write(rnote(note));  delay(10);  roomba.write(64 / rlong);   delay(10);
                    }
                    
                    
                    bool rwakeup() {
                        bool ret = getSensors(6, buf, 52);
                        Serial.print("wakeup: ");
                        Serial.print(ret);
                        if (!ret) {
                            for (int ii = 1; ii < ROOMBA_WAKE_COUNT; ii++)
                            {
                                for (int jj = 0; jj < 3; jj++) {
                                    digitalWrite(ddPin, HIGH); delay(10); 
                                    digitalWrite(ddPin, LOW); delay(2);
                                }
                                delay(100);
                                roomba.write(128);
                                if (getSensors(6, buf, 52)) {
                                    ret = true;
                                    break;
                                }
                                Serial.print("-");
                            }
                        }
                        Serial.println(ret);
                        return ret;
                    }
                    
                    bool getSensors(uint8_t packetID, uint8_t* dest, uint8_t len) {
                        roomba.write(142);
                        delay(100);
                        roomba.write(packetID);
                        delay(100);
                        return getData(dest, len);
                    }
                    
                    
                    bool getData(uint8_t* dest, uint8_t len)
                    {
                        while (len-- > 0)
                        {
                            unsigned long startTime = millis();
                            while (!roomba.available())
                            {
                                // Look for a timeout
                                if (millis() > startTime + ROOMBA_READ_TIMEOUT)
                                    return false; // Timed out
                            }
                            *dest++ = roomba.read();
                        }
                        return true;
                    }
                    
                    //for sensorgetting
                    int getPacketSize(int p) {
                        return packetSizes[p - 1];
                    }
                    int getPacketOffset(int p) {
                        int i = 0;
                        for (int s = 1; s < p; s++) {
                            i += getPacketSize(s);
                        }
                        return i;
                    }
                    
                    //read sensors
                    void readsensors()
                    {
                    
                        if (getSensors(6, buf, 52)) {
                    
                            int off = 0;
                    
                            // Battery Checks
                            off = getPacketOffset(21);
                            chargingState = buf[off + 0];
                            voltage = buf[off + 2] + 256 * buf[off + 1];
                            temp = buf[off + 5];
                            battery_Current_mAh = buf[off + 7] + 256 * buf[off + 6];
                            battery_Total_mAh = buf[off + 9] + 256 * buf[off + 8];
                    
                            if (battery_Total_mAh == 0) battery_Total_mAh = 1;
                            int nBatPcent = battery_Current_mAh * 100 / battery_Total_mAh;
                            battery_percent = nBatPcent;
                    
                            //Oi Mode
                            off = getPacketOffset(35);
                            OiMode = buf[off + 0];
                    
                            //ChargeSource
                            off = getPacketOffset(34);
                            ChargeSource = buf[off + 0];
                    
                    
                            send(msg1_3.set(temp));  delay(100);
                            send(msg1_4.set(battery_percent));  delay(100);
                            send(msg1_2.set(round(voltage / 10), 1));  delay(100);
                            send(msg2_5.set(battery_Current_mAh));  delay(100);
                            send(msg1_1.set(ChargeTypes[chargingState]));  delay(100);
                            send(msg2_2.set(ChargeSource));  delay(100);
                    
                            //send(msg2_5.set(chargingState));  // Send info value to gw
                            //send(msg2_5.set("charging state"));  // Send info value to gw
                            //send(msg2_5.set(battery_Total_mAh));  // Send info value to gw
                            //send(msg2_1.set(OiTypes[OiMode]));  // Send info value to gw
                            lastsensorread = millis();
                    
                        }
                        else { send(msg1_1.set("roomba is off")); }  // Send info value to gw
                    }
                    
                    void defsongs() {
                        uint8_t zero = 0;
                        roomba.write(128);  delay(100); roomba.write(131);  delay(100); //[128 131](Start the command stream and change roomba mode to "Safe" mode)
                        roomba.write(140);  delay(100); roomba.write(zero); delay(100); //[140 0](Start song definition and define the first song, song number 0)
                        roomba.write(25);   //[16](16 notes will be sent for song number 0)
                        play('E', 4);       //[76 16](play Mi sound for 1 / 4 seconds) // E
                        play('E', 4);
                        play('E', 2);
                        play('E', 4);
                        play('E', 4);
                        play('E', 2);       //[76 32](play Mi sound for 1 / 2 seconds)
                        play('E', 4);
                        play('G', 4);
                        play('C', 4);
                        play('D', 4);
                        play('E', 1);
                    
                        play('F', 4);
                        play('F', 4);
                        play('F', 2);
                    
                        play('F', 4);
                        play('E', 4);
                        play('E', 2);
                    
                        play('E', 4);
                        play('D', 4);
                        play('D', 4);
                        play('E', 4);
                        play('D', 1);
                        delay(100);
                        roomba.write(128);
                    }
                    
                    int rnote(char note) {
                        int command = 31;
                        switch (note) {
                        case 'C': command = 72; break;
                        case 'D': command = 74; break;
                        case 'E': command = 76; break;
                        case 'F': command = 77; break;
                        case 'G': command = 79; break;
                        }
                        return command;
                    }
                    
                    
                    Z Offline
                    Z Offline
                    zen85
                    wrote on last edited by zen85
                    #17
                    // Enable debug prints to serial monitor
                    #define MY_DEBUG
                    
                    // Enable and select radio type attached
                    #define MY_RADIO_NRF24
                    //#define MY_RADIO_RFM69
                    
                    // Enable repeater functionality for this node
                    #define MY_REPEATER_FEATURE
                    
                    #define CHILD_ID_BATT_TEMP          100  // Id of the 2nd msg1_3
                    #define CHILD_ID_BATT_PROC          101   // Id of the 2nd msg1_4
                    #define CHILD_ID_BATT_VOLT          102   // Id of the 2nd msg1_2
                    #define CHILD_ID_BATT_AH            103   // Id of the 2nd msg2_5
                    #define CHILD_ID_BATT_CHARGE_TYPE   104   // Id of the 2nd msg1_1
                    #define CHILD_ID_BATT_CHARGE_SOURCE 105   // Id of the 2nd msg2_2
                    
                    
                    #include <MySensors.h>
                    #include <SoftwareSerial.h>
                    
                    //#define RELAY_1  5  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
                    //#define NUMBER_OF_RELAYS 2 // Total number of attached relays
                    //#define RELAY_ON 1  // GPIO value to write to turn on attached relay
                    //#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
                    
                    #define NUMBER_OF_FUNCTION 7 
                    #define NUMBER_OF_SENSORS 6
                    #define ROOMBA_READ_TIMEOUT 300
                    #define ROOMBA_WAKE_COUNT 10
                    int ddPin = 6;
                    
                    int rxPin = 3;
                    int txPin = 4;
                    int ledPin = 13;
                    
                    SoftwareSerial roomba(rxPin, txPin);
                    
                    const char SWITCH_NAMES[NUMBER_OF_FUNCTION][14] = { "Roomba-Stop","Roomba-Dock","Roomba-Clean","Roomba-Spot","Roomba-Max","Roomba-Power","Roomba-Play" };
                    const char SENSORS_NAMES[NUMBER_OF_SENSORS][24] = { "Roomba-Batt-Temp","Roomba-Batt-Proc","Roomba-Batt-Volt", "Roomba-Batt-mAH" , "Roomba-Batt-CHt" , "Roomba-Batt-CHs" };
                    
                    
                    uint8_t buf[52];
                    boolean lowBattery = true; // Acts as a debounce
                    long battery_Current_mAh = 0;
                    long battery_Total_mAh = 0;
                    long battery_percent = 0;
                    boolean DeadBattery = false;
                    boolean FullBattery = true;
                    unsigned long chargingState = 0;
                    long voltage = 0;
                    long temp = 0;
                    long OiMode = 0;
                    long ChargeSource = 0;
                    
                    long sensorfrequency = 300000; // 300000 = 5 min - frequency the sensors are read
                    long lastsensorread = 0; // when were the sensors read the last time
                    unsigned long lastsensorssend = 0;
                    
                    const char ChargeTypes[6][34] = { "Not charging","Reconditioning Charging","Full Charging","Trickle Charging","Waiting","Charging Fault Condition" };
                    const char OiTypes[4][14] = { "Off","Passive","Safe","Full" };
                    
                    int packetSizes[58] = {
                        0,0,0,0,0,0, //1-6
                        1,1,1,1,1,1,1,1,1,1,1,1, //7-18
                        2,2, //19-20
                        1, //21
                        2,2, //22-23
                        1, //24
                        2,2,2,2,2,2,2, //25-31
                        1, //32
                        2, //33
                        1,1,1,1,1, //34-38
                        2,2,2,2,2,2, //39-44
                        1, //45
                        2,2,2,2,2,2, //46-51
                        1,1, //52-53
                        2,2,2,2, //54-57
                        1 //58
                    };
                    #define bumpright (sensorbytes[0] & 0x01)
                    #define bumpleft  (sensorbytes[0] & 0x02)
                    
                    
                    MyMessage msg1_3(CHILD_ID_BATT_TEMP, V_TEMP); //status of Temperature
                    MyMessage msg1_4(CHILD_ID_BATT_PROC, V_PH); //status of Charge [%]
                    MyMessage msg1_2(CHILD_ID_BATT_VOLT, V_VOLTAGE); //status of Voltage
                    MyMessage msg2_5(CHILD_ID_BATT_AH, V_CURRENT); //status of mAH
                    MyMessage msg1_1(CHILD_ID_BATT_CHARGE_TYPE, V_TEXT); //status of charget type
                    MyMessage msg2_2(CHILD_ID_BATT_CHARGE_SOURCE, V_TEXT); //status of charger source
                    
                    void setup() {
                        pinMode(ddPin, OUTPUT);
                        digitalWrite(ddPin, LOW);
                        Serial.begin(115200);
                        while (!Serial) {
                            ; // wait for serial port to connect. Needed for native USB port only
                        }
                        roomba.begin(115200);
                        //Serial.println("Sending start command...");
                        //delay(1000);
                        //// set up ROI to receive commands
                        defsongs();
                        delay(500);
                        rstop();
                        Serial.println("Ready to go!");
                    }
                    
                    void presentation()
                    {
                        // Send the sketch version information to the gateway and Controller
                        sendSketchInfo("Roomba", "1.2");
                    
                        for (int sensor = 0; sensor < NUMBER_OF_FUNCTION; sensor++) {
                            // Register all sensors to gw (they will be created as child devices)
                            present(sensor, S_BINARY, SWITCH_NAMES[sensor]);
                            delay(100);
                        }
                        present(CHILD_ID_BATT_TEMP, S_TEMP, SENSORS_NAMES[0]); delay(100);
                        present(CHILD_ID_BATT_PROC, S_WATER_QUALITY, SENSORS_NAMES[1]); delay(100);
                        present(CHILD_ID_BATT_VOLT, S_MULTIMETER, SENSORS_NAMES[2]);    delay(100);
                        present(CHILD_ID_BATT_AH, S_MULTIMETER, SENSORS_NAMES[3]);  delay(100);
                        present(CHILD_ID_BATT_CHARGE_TYPE, S_INFO, SENSORS_NAMES[4]); delay(100);
                        present(CHILD_ID_BATT_CHARGE_SOURCE, S_INFO, SENSORS_NAMES[5]); delay(100);
                    }
                    
                    void loop() {
                        unsigned long now = millis();
                        if (now > lastsensorssend + sensorfrequency)
                        {
                            readsensors();
                            lastsensorssend = now;
                        }
                    }
                    
                    
                    void receive(const MyMessage &message) {
                      // We only expect one type of message from controller. But we better check anyway.
                      if (message.type == V_LIGHT) {
                        int mySensor = message.sensor;
                        int myComand = message.getBool();
                    
                        //Serial.print(message.sensor-1+RELAY_1);
                    
                        if (mySensor == 0) {
                          if (myComand == 1) {
                            Serial.println("Clean");
                            //clean();
                            rcommand(135);
                          }
                          else {
                            Serial.println("Stopp1");
                            //halt();
                            rstop();
                          }
                        }
                    
                        if (mySensor == 1) {
                          if (myComand == 1) {
                            Serial.println("dock");
                            //dock();
                            rcommand(143);
                          }
                          else {
                            Serial.println("Stopp2");
                            //halt();
                            rstop();
                          }
                        }
                        if (mySensor == 2) {
                          if (myComand == 1) {
                            Serial.println("song");
                            //dock();
                            rcommand(141);
                            rsong(0);
                          }
                          else {
                            Serial.println("Stopp2");
                            //halt();
                            rstop();
                          }
                        }
                    
                      }
                    }
                    
                    void halt() {
                      ;
                      roomba.write(131);  // SAFE
                      byte j = 0x00;
                      roomba.write(137);
                      roomba.write(j);
                      roomba.write(j);
                      roomba.write(j);
                      roomba.write(j);
                    }
                    
                    void dock() {
                      delay(1000);
                      roomba.write(143);
                    }
                    
                    void clean() {
                      delay(1000);
                      roomba.write(135);
                    }
                    
                    void rstop() {
                        if (rwakeup()) {
                            roomba.write(128);  delay(100);
                            roomba.write(131);  delay(100);
                            roomba.write(137);  delay(100);
                            byte j = 0x00;
                            roomba.write(j); delay(100);
                            roomba.write(j); delay(100);
                            roomba.write(j); delay(100);
                            roomba.write(j); delay(100);
                            roomba.write(128);
                        }
                    
                    }
                    
                    void rsong(int b) {
                        roomba.write(b); delay(100);
                    }
                    
                    
                    
                    void rcommand(int command) {
                        if (rwakeup()) {
                            roomba.write(128);  delay(100);
                            roomba.write(131);  delay(100);
                            roomba.write(command);
                        }
                    }
                    
                    void play(char note, int rlong) {
                        roomba.write(rnote(note));  delay(10);  roomba.write(64 / rlong);   delay(10);
                    }
                    
                    
                    bool rwakeup() {
                        bool ret = getSensors(6, buf, 52);
                        Serial.print("wakeup: ");
                        Serial.print(ret);
                        if (!ret) {
                            for (int ii = 1; ii < ROOMBA_WAKE_COUNT; ii++)
                            {
                                for (int jj = 0; jj < 3; jj++) {
                                    digitalWrite(ddPin, HIGH); delay(10); 
                                    digitalWrite(ddPin, LOW); delay(2);
                                }
                                delay(100);
                                roomba.write(128);
                                if (getSensors(6, buf, 52)) {
                                    ret = true;
                                    break;
                                }
                                Serial.print("-");
                            }
                        }
                        Serial.println(ret);
                        return ret;
                    }
                    
                    bool getSensors(uint8_t packetID, uint8_t* dest, uint8_t len) {
                        roomba.write(142);
                        delay(100);
                        roomba.write(packetID);
                        delay(100);
                        return getData(dest, len);
                    }
                    
                    
                    bool getData(uint8_t* dest, uint8_t len)
                    {
                        while (len-- > 0)
                        {
                            unsigned long startTime = millis();
                            while (!roomba.available())
                            {
                                // Look for a timeout
                                if (millis() > startTime + ROOMBA_READ_TIMEOUT)
                                    return false; // Timed out
                            }
                            *dest++ = roomba.read();
                        }
                        return true;
                    }
                    
                    //for sensorgetting
                    int getPacketSize(int p) {
                        return packetSizes[p - 1];
                    }
                    int getPacketOffset(int p) {
                        int i = 0;
                        for (int s = 1; s < p; s++) {
                            i += getPacketSize(s);
                        }
                        return i;
                    }
                    
                    //read sensors
                    void readsensors()
                    {
                    
                        if (getSensors(6, buf, 52)) {
                    
                            int off = 0;
                    
                            // Battery Checks
                            off = getPacketOffset(21);
                            chargingState = buf[off + 0];
                            voltage = buf[off + 2] + 256 * buf[off + 1];
                            temp = buf[off + 5];
                            battery_Current_mAh = buf[off + 7] + 256 * buf[off + 6];
                            battery_Total_mAh = buf[off + 9] + 256 * buf[off + 8];
                    
                            if (battery_Total_mAh == 0) battery_Total_mAh = 1;
                            int nBatPcent = battery_Current_mAh * 100 / battery_Total_mAh;
                            battery_percent = nBatPcent;
                    
                            //Oi Mode
                            off = getPacketOffset(35);
                            OiMode = buf[off + 0];
                    
                            //ChargeSource
                            off = getPacketOffset(34);
                            ChargeSource = buf[off + 0];
                    
                    
                            send(msg1_3.set(temp));  delay(100);
                            send(msg1_4.set(battery_percent));  delay(100);
                            send(msg1_2.set(round(voltage / 10), 1));  delay(100);
                            send(msg2_5.set(battery_Current_mAh));  delay(100);
                            send(msg1_1.set(ChargeTypes[chargingState]));  delay(100);
                            send(msg2_2.set(ChargeSource));  delay(100);
                    
                            //send(msg2_5.set(chargingState));  // Send info value to gw
                            //send(msg2_5.set("charging state"));  // Send info value to gw
                            //send(msg2_5.set(battery_Total_mAh));  // Send info value to gw
                            //send(msg2_1.set(OiTypes[OiMode]));  // Send info value to gw
                            lastsensorread = millis();
                    
                        }
                        else { send(msg1_1.set("roomba is off")); }  // Send info value to gw
                    }
                    
                    void defsongs() {
                        uint8_t zero = 0;
                        roomba.write(128);  delay(100); roomba.write(131);  delay(100); //[128 131](Start the command stream and change roomba mode to "Safe" mode)
                        roomba.write(140);  delay(100); roomba.write(zero); delay(100); //[140 0](Start song definition and define the first song, song number 0)
                        roomba.write(25);   //[16](16 notes will be sent for song number 0)
                        play('E', 4);       //[76 16](play Mi sound for 1 / 4 seconds) // E
                        play('E', 4);
                        play('E', 2);
                        play('E', 4);
                        play('E', 4);
                        play('E', 2);       //[76 32](play Mi sound for 1 / 2 seconds)
                        play('E', 4);
                        play('G', 4);
                        play('C', 4);
                        play('D', 4);
                        play('E', 1);
                    
                        play('F', 4);
                        play('F', 4);
                        play('F', 2);
                    
                        play('F', 4);
                        play('E', 4);
                        play('E', 2);
                    
                        play('E', 4);
                        play('D', 4);
                        play('D', 4);
                        play('E', 4);
                        play('D', 1);
                        delay(100);
                        roomba.write(128);
                    }
                    
                    int rnote(char note) {
                        int command = 31;
                        switch (note) {
                        case 'C': command = 72; break;
                        case 'D': command = 74; break;
                        case 'E': command = 76; break;
                        case 'F': command = 77; break;
                        case 'G': command = 79; break;
                        }
                        return command;
                    }
                    

                    i love this project. i am the owner of a roomba 620 and hooked it up to a arduino-mega. putting "clean()" in the code does what it should and the radiomodules are working fine. but it seems that i dont get values from the sensors and so nothing is showing up in homeassistant... :(

                    i checked the wiring about 5 times already and since starting for example "clean()" works i think it is a different issue...

                    did anyone else try this and ran into the same problem?

                    1 Reply Last reply
                    0
                    • B Offline
                      B Offline
                      banda banda
                      Banned
                      wrote on last edited by mfalkvidd
                      #18

                      there is plenty of space for a nano or pro mini. wemos mini or nodemcu should also fit
                      (spam links removed by moderator)

                      1 Reply Last reply
                      0

                      Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                      Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                      With your input, this post could be even better 💗

                      Register Login
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      13

                      Online

                      12.0k

                      Users

                      11.2k

                      Topics

                      113.4k

                      Posts


                      Copyright 2025 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • MySensors
                      • OpenHardware.io
                      • Categories
                      • Recent
                      • Tags
                      • Popular