Navigation

    • Register
    • Login
    • OpenHardware.io
    • Categories
    • Recent
    • Tags
    • Popular
    1. Home
    2. BartE
    3. Best
    • Profile
    • Following
    • Followers
    • Topics
    • Posts
    • Best
    • Groups

    Best posts made by BartE

    • RFID Garage door opener

      This sketch is to open a Garage door with an mifare RIFD-tag

      For an Arduino Nano v3 wiring :

      • rf24l01+ as descibed on the MySensors website
      • MFRC522 reader/writer as described above EXCEPT for pin D9 and D10: connect RST i.s.o. pin D9 to pin D7 and connect SDA(SS) i.s.o. pin D10 to pin D8
      • LED with 470ohm resistor between GMD and pin A3
      • push button between GND and pin D5
      • 5v relays coil between GND and pin D4 -> switch pins of the relays should be connected in parallel with your garage door push button.

      Features:

      • This project can record up to 18 RFID-"tags"
      • These card IDs are stored in to EEPROM by keeping them next to the RFID reader when the system in program mode. (Slow blinking LED) When a card is accepted as new card the LED will blink fast for a short time.
      • To keep the master-tags (choose your own) next to the RFID reader when pressing the push button. To clear all cards (except the master card) press the push button in program mode for 6 seconds. The LED will now fast blink for a couple of seconds.
      • Your garage your can be opened by keep a registered RFID tag next to the reader or by clicking the open icon on lock node presented by this plugin.
      • By by-passing the alarm node presented by this plug in the RFID will be temporarily disabled.
      • When an incorrect (not registered) RFID tag is scanned the alarm is triggered to detect illegal scan attempts
        RFIDSketch.png

      Used RFID reader can be found here:

      The Sketch code:

      /*
       * ----------------------------------------------------------------------------
       * This is a MFRC522 library example; see https://github.com/miguelbalboa/rfid
       * for further details and other examples.
       * 
       * NOTE: The library file MFRC522.h has a lot of useful info. Please read it.
       * 
       * Released into the public domain.
       * ----------------------------------------------------------------------------
       * Example sketch/program showing how to read data from a PICC (that is: a RFID
       * Tag or Card) using a MFRC522 based RFID Reader on the Arduino SPI interface.
       * 
       * When the Arduino and the MFRC522 module are connected (see the pin layout
       * below), load this sketch into Arduino IDE then verify/compile and upload it.
       * To see the output: use Tools, Serial Monitor of the IDE (hit Ctrl+Shft+M).
       * When you present a PICC (that is: a RFID Tag or Card) at reading distance
       * of the MFRC522 Reader/PCD, the serial output will show the ID/UID, type and
       * any data blocks it can read. Note: you may see "Timeout in communication"
       * messages when removing the PICC from reading distance too early.
       * 
       * If your reader supports it, this sketch/program will read all the PICCs
       * presented (that is: multiple tag reading). So if you stack two or more
       * PICCs on top of each other and present them to the reader, it will first
       * output all details of the first and then the next PICC. Note that this
       * may take some time as all data blocks are dumped, so keep the PICCs at
       * reading distance until complete.
       * 
       * Typical pin layout used:
       * -----------------------------------------------------------------------------------------
       *             MFRC522      Arduino       Arduino   Arduino    Arduino          Arduino
       *             Reader/PCD   Uno           Mega      Nano v3    Leonardo/Micro   Pro Micro
       * Signal      Pin          Pin           Pin       Pin        Pin              Pin
       * -----------------------------------------------------------------------------------------
       * RST/Reset   RST          9             5         D9         RESET/ICSP-5     RST
       * SPI SS      SDA(SS)      10            53        D10        10               10
       * SPI MOSI    MOSI         11 / ICSP-4   51        D11        ICSP-4           16
       * SPI MISO    MISO         12 / ICSP-1   50        D12        ICSP-1           14
       * SPI SCK     SCK          13 / ICSP-3   52        D13        ICSP-3           15
       */
      
      /*
       RFID Garagedoor opener by Bart Eversdijk
       
       This sketch is to open a Garage door with an mifare RIFD-tag 
        
        For an Arduino Nano v3
        Connection wiring :
          - nrf24l01+ as descibed on the MySensors website
          - MFRC522 reader/writer as described above EXCEPT for pin D9 and D10:  connect RST i.s.o. pin D9 to pin D7 and connect SDA(SS) i.s.o. pin D10 to pin D8 
          - LED with 470ohm resistor between GMD and pin A3 
          - push button between GND and pin D5
          - 5v relays coil between GND and  pin D4 -> switch pins of the relays should be connected in parallel with your garage door push button. 
        
        Features:
        This project can record up to 18 RFID-"tags"
        These card IDs are stored in to EEPROM by keeping them next to the RFID reader when the system in program mode. (Slow blinking LED) When a card is accepted as new card the LED will blink fast for a short time.
        To keep the master-tags (choose your own) next to the RFID reader when pressing the push button. To clear all cards (except the master card) press the push button in program mode for 6 seconds. The LED will now fast blink for a couple of seconds.
        
        Your garage your can be opened by keep a registered RFID tag next to the reader or by clicking the open icon on lock node presented by this plugin.
        By by-passing the alarm node presented by this plug in the RFID will be temporarily disabled.
        When an incorrect (not registered) RFID tag is scanned the alarm is triggered to detect illegal scan attempts   
      
      */
      
      #include <SPI.h>
      #include <MFRC522.h>
      #include <MySensor.h> 
      #include <Bounce2.h>
      
      #define RF_INIT_DELAY   125
      #define ONE_SEC         1000
      #define MAX_CARDS       18
      #define PROG_WAIT       10
      #define HEARTBEAT       10
      #define BAUD            115200
      
      /*Pin definitions*/
      #define LED_PIN         A3
      #define GARAGEPIN       4
      #define SWITCH_PIN      5
      #define RST_PIN		7		//  MFRC 
      #define SS_PIN		8		//  MFRC 
      
      MFRC522      mfrc522(SS_PIN, RST_PIN);	// Create MFRC522 instance
      MFRC522::Uid olduid;
      MFRC522::Uid masterkey = { 10, {0,0,0,0, 0,0,0,0, 0,0 },  0 };
      
      byte       countValidCards  = 0;
      MFRC522::Uid validCards[MAX_CARDS];
      
      void       ShowCardData(MFRC522::Uid* uid);
      bool       sameUid(MFRC522::Uid* old, MFRC522::Uid* check);
      void       copyUid(MFRC522::Uid* src, MFRC522::Uid* dest);
      bool       isValidCard(MFRC522::Uid* uid);
      int        releasecnt = 0;
      
      #define    CHILD_ID_ALARM    1
      #define    CHILD_ID_LOCK     2
      MySensor   gw;
      Bounce     debouncer = Bounce();
      
      int        oldSwitchValue=-1;
      int        switchValue = 0;
      long       timer = -1;
      bool       programmode = false;
      bool       ledon;
      int        programTimer = 0;
      bool       armed = true;
      unsigned long lastTime = 0;
      
      MyMessage  lockMsg(CHILD_ID_LOCK,          V_LOCK_STATUS);
      MyMessage  lockArmMsg(CHILD_ID_ALARM,      V_ARMED);
      MyMessage  wrongMsg(CHILD_ID_ALARM,        V_TRIPPED);
      
      void setup() {
      	Serial.begin(BAUD);		// Initialize serial communications with the PC
              pinMode(GARAGEPIN, OUTPUT);     // Initialise in/output ports
              
              // Make sure MFRC will be disabled on the SPI bus
              pinMode(RST_PIN, OUTPUT);     
              digitalWrite(RST_PIN, LOW);
              pinMode(SS_PIN, OUTPUT);     
              digitalWrite(SS_PIN, LOW);
      
              pinMode(LED_PIN, OUTPUT);
              digitalWrite(LED_PIN, LOW);
              // Setup the button
              pinMode(SWITCH_PIN, INPUT);
              // Activate internal pull-up
              digitalWrite(SWITCH_PIN, HIGH);
      
              // After setting up the button, setup debouncer
              debouncer.attach(SWITCH_PIN);
              debouncer.interval(5);
      
              // Init mysensors library
              gw.begin(incomingMessage, 5);
              gw.sendSketchInfo("RFID Garage", "1.1"); delay(RF_INIT_DELAY);
              
              // Register all sensors to gw (they will be created as child devices)
              gw.present(CHILD_ID_LOCK, S_LOCK);      delay(RF_INIT_DELAY);
              gw.present(CHILD_ID_ALARM, S_MOTION);   delay(RF_INIT_DELAY);
      
              recallEeprom();
              
              // Init MFRC RFID sensor
      	SPI.begin();			// Init SPI bus
      	mfrc522.PCD_Init();		// Init MFRC522
      	ShowReaderDetails();	        // Show details of PCD - MFRC522 Card Reader details
      
              gw.send(lockArmMsg.set(armed));
              Serial.println(F("Init done..."));
      }
      
      void loop() {
              timer++;
              delay(HEARTBEAT);
              gw.process();
              debouncer.update();
      
              // Get the update value
              int switchValue = debouncer.read();
              if (switchValue != oldSwitchValue) {
                // Send in the new value
                Serial.print (F("Switch "));
                Serial.println (switchValue);
                
                if (switchValue && programmode) {
                     lastTime     = millis() / 1000;
                }
                
                if (!switchValue && programmode && lastTime > 0) {
                     if ( (millis() / 1000) - lastTime > 3) {
                          Serial.println(F("Reset all cards"));  
                          countValidCards  = 0;
                          blinkFast(50);
                     } else {
                        Serial.println(F("Program off"));  
                        digitalWrite(LED_PIN, LOW);
                        programmode = false;
                        
                        storeEeprom();
                     }
                }
                
                if (!switchValue)   {
                    programTimer = 0;
                }
                oldSwitchValue = switchValue;
              }
              
              if (programmode && ((timer % (ONE_SEC / HEARTBEAT)) == 0 ))  {
                  ledon = !ledon;
                  digitalWrite(LED_PIN, ledon);
                  programTimer++;
      
                  // Stop program mode after 20 sec inactivity
                  if (programTimer > PROG_WAIT)  {
                     programmode = false;
                     digitalWrite(LED_PIN, false);
                     Serial.println(F("Program expired"));  
                  }
              }
              
              if ((timer % (200 / HEARTBEAT)) == 0 )   {
                   // Look for new cards
                   if ( ! mfrc522.PICC_IsNewCardPresent()) {
                        if (releasecnt > 0)   {
                            releasecnt--;
                            if (!releasecnt)  {
                                olduid.size = 0;
                                Serial.println(F("release"));
                            }
                          }
          		return;
          	    }
                  releasecnt = 5;
          
          	   // Select one of the cards
          	   if ( ! mfrc522.PICC_ReadCardSerial()) {
          		return;
          	   }
          
                 // Dump debug info about the card; PICC_HaltA() is automatically called
          	   //mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
                 if (!olduid.size || !sameUid(&(mfrc522.uid), &olduid))  {
                      ShowCardData(&(mfrc522.uid));
                      copyUid(&(mfrc522.uid), &olduid);
                      if ( isValidCard(&olduid) )   {
                           OpenDoor(programmode);
                      } else  {
                        
                         if (sameUid(&(mfrc522.uid), &masterkey)) {
                             // Only switch in program mode when mastercard is found AND the program button is pressed
                             if (switchValue)  {
                               Serial.println(F("Program mode"));
                               programmode = true;
                               programTimer = 0;
                               lastTime     = 0;
                             }
                         } else {
                             if (programmode) {
                               Serial.println(F("new card"));
                               programTimer = 0;
                               
                               if (countValidCards < MAX_CARDS)
                               {
                                  // Add card to list...
                                  copyUid(&(mfrc522.uid), &validCards[countValidCards]);
                                  countValidCards++;
                                  blinkFast(15);
                               }
                             } else {
                               Serial.println(F("Invalid card"));
                               if (armed) {
                                  gw.send(wrongMsg.set(1));
                                  delay(2000);
                                  gw.send(wrongMsg.set(0));
                               }
                             }
                         }
                      }
                 }
              }
      }
      
      void ShowCardData(MFRC522::Uid* uid) {
              Serial.print(F("Card UID:"));
      	for (byte i = 0; i < uid->size; i++) {
      		if(uid->uidByte[i] < 0x10) {
      			Serial.print(F(" 0"));
      		} else {
      			Serial.print(F(" "));
                      }
      		Serial.print(uid->uidByte[i], HEX);
      	} 
      	Serial.println();
      }
      
      void copyUid(MFRC522::Uid* src, MFRC522::Uid* dest)
      {
          dest->size = src->size;
          dest->sak  = src->sak;
          
          for (byte i = 0; i < src->size; i++) {
        	dest->uidByte[i] = src->uidByte[i];
          }
      }
      
      bool sameUid(MFRC522::Uid* old, MFRC522::Uid* check)
      {
          if (old->size != check->size) {
             return false;
          }
          for (byte i = 0; i < old->size; i++) {
        	if (old->uidByte[i] != check->uidByte[i]) {
                  return false;
              }
          }
          return true;
      }
      
      bool isValidCard(MFRC522::Uid* uid)
      {
            for (byte i = 0; i < countValidCards; i++)  {
                if (validCards[i].size != uid->size)  {
                    break;
                }
                for (int j = 0; j < uid->size; j++) {
                    if (validCards[i].uidByte[j] != uid->uidByte[j])  {
                        break;
                    }
                    if (j == (uid->size - 1)) {  
                        return true;
                    }
                }
            }
            return false;
      }
      
      
      void storeEeprom()
      {
          byte address = 0;
          gw.saveState(address++, countValidCards);
          
          for (byte i = 0; i < countValidCards; i++) {
             gw.saveState(address++, validCards[i].size);
             for (byte j = 0; j < 10; j++) {
                gw.saveState(address++, validCards[i].uidByte[j]);
             } 
          }
      }
      
      void recallEeprom()
      {
          byte address = 0;
          
          countValidCards = gw.loadState(address++);
          if (countValidCards > MAX_CARDS) {
             Serial.println(F("Not a valid EEPROM reading set to default"));
             countValidCards = 0;
             storeEeprom();
             return;
          }
          
          for (byte i = 0; i < countValidCards; i++)  {
             validCards[i].size = gw.loadState(address++);
             for (byte j = 0; j < 10; j++)  {
                validCards[i].uidByte[j] = gw.loadState(address++);
             } 
          }
        
      }
      
      void blinkFast(int times)
      {
          for (int i = 0; i < times; i++) { 
             ledon = !ledon;
             digitalWrite(LED_PIN, ledon);
             delay(100);
          }
      }
      
      void OpenDoor(bool fakeOpen)
      {
          Serial.println(F("Open door!"));
          gw.send(lockMsg.set(false));
          
          if (!fakeOpen) { 
            digitalWrite(LED_PIN, HIGH);
            digitalWrite(GARAGEPIN, HIGH); 
          }
          delay(1000);
          
          if (!fakeOpen) { 
            digitalWrite(GARAGEPIN, LOW); 
            digitalWrite(LED_PIN, LOW);
          }
          
          gw.send(lockMsg.set(true));
      }
      
      void ShowReaderDetails() {
      	// Get the MFRC522 software version
      	byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
      	Serial.print(F("MFRC522 Software Version: 0x"));
      	Serial.print(v, HEX);
      	if (v == 0x91) {
      		Serial.print(F(" = v1.0"));
              } else if (v == 0x92) {
      		Serial.print(F(" = v2.0"));
              } else {
      		Serial.print(F(" (unknown)"));
              }
      	Serial.println("");
      	
              // When 0x00 or 0xFF is returned, communication probably failed
      	if ((v == 0x00) || (v == 0xFF)) {
      		Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?"));
      	}
      }
      
      
      void incomingMessage(const MyMessage &message) 
      {
         if (message.type == V_LOCK_STATUS) {
           // Change relay state
           if (!message.getBool())  {
              OpenDoor(false);
           }
        
           // Write some debug info
           Serial.print(F("Lock status: "));
           Serial.println(message.getBool());
         }
         else 
         {
           if (message.type == V_ARMED)  {
             // Change relay state
             armed = message.getBool();
        
             // Write some debug info
             Serial.print(F("Arm status: "));
             Serial.println(message.getBool());
           }
           else
           {
             // Write some debug info
             Serial.print(F("Incoming msg type: "));
             Serial.print(message.type);
             Serial.print(F(" id: "));
             Serial.print(message.sensor);
             Serial.print(F(" content: "));
             Serial.println(message.getInt());
           }
         }
      }
      
      posted in My Project
      BartE
      BartE
    • IR Record and Playback module

      On special request i've created a IR (InfraRed remote) record and playback sensor.
      This is based on the example IR sensor but now one can record a IR - signal from an remote and let your controller send the IR code on request. http://www.mysensors.org/build/ir

      Up to 10 codes can be recorded and playback

      Please note this plugin relies on a message type which is not yet available in the MySensors core (a pull request has been made)
      This Arduino library https://github.com/z3t0/Arduino-IRremote/releases is used for decoding and encoding:

      /**
       * The MySensors Arduino library handles the wireless radio link and protocol
       * between your home built sensors/actuators and HA controller of choice.
       * The sensors forms a self healing radio network with optional repeaters. Each
       * repeater and gateway builds a routing tables in EEPROM which keeps track of the
       * network topology allowing messages to be routed to nodes.
       *
       * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
       * Copyright (C) 2013-2015 Sensnology AB
       * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
       *
       * Documentation: http://www.mysensors.org
       * Support Forum: http://forum.mysensors.org
       *
       * This program is free software; you can redistribute it and/or
       * modify it under the terms of the GNU General Public License
       * version 2 as published by the Free Software Foundation.
       *
       *******************************
       *
       * REVISION HISTORY
       * Version 1.0 - Changed for MySensors usage by Bart Eversdijk
       * 
       * DESCRIPTION
       *
       * IRrecord: record and play back IR signals as a minimal 
       * An IR detector/demodulator must be connected to the input RECV_PIN.
       * An IR LED must be connected to the output PWM pin 3.
       * A button must be connected to the input BUTTON_PIN; this is the
       * send button.
       * A visible LED can be connected to STATUS_PIN to provide status.
       *
       * The logic is:
       * If the button is pressed, send the IR code.
       * If an IR code is received, record it.
       *
       * Version 0.11 September, 2009
       * Copyright 2009 Ken Shirriff
       * http://arcfn.com
       */
      
      #include <MySensor.h>
      #include <SPI.h>
      #include <IRremote.h>  // https://github.com/z3t0/Arduino-IRremote/releases
      
      int RECV_PIN     = 8;
      #define NODEID   5
      #define CHILD_1  2  // childId
      
      #define MY_RAWBUF  50
      const char * TYPE2STRING[] = {
      		"UNKONWN",
      		"RC5",
      		"RC6",
      		"NEC",
      		"Sony",
      		"Panasonic",
      		"JVC",
      		"SAMSUNG",
      		"Whynter",
      		"AIWA RC T501",
      		"LG",
      		"Sanyo",
      		"Mitsubishi",
      		"Dish",
      		"Sharp",
      		"Denon"
      };
      #define Type2String(x)   TYPE2STRING[x < 0 ? 0 : x]
      #define AddrTxt          F(" addres: 0x")
      #define ValueTxt         F(" value: 0x")
      #define NATxt            F(" - not implemented/found")
      
      // Raw or unknown codes requires an Arduino with a larger memory like a MEGA and some changes to store in EEPROM (now max 255 bytes)
      // #define IR_SUPPORT_UNKNOWN_CODES
      typedef union
      {
        struct
        {
          decode_type_t type;            // The type of code
          unsigned long value;           // The data bits if type is not raw
          int           len;             // The length of the code in bits
          unsigned int  address;         // Used by Panasonic & Sharp [16-bits]
        } code;
      #ifdef IR_SUPPORT_UNKNOWN_CODES      
        struct
        {
          decode_type_t type;             // The type of code
          unsigned int  codes[MY_RAWBUF];
          byte          count;           // The number of interval samples
        } raw;
      #endif
      } IRCode;
      
      #define           MAX_IR_CODES     10
      IRCode            StoredIRCodes[MAX_IR_CODES];
      
      IRrecv            irrecv(RECV_PIN);
      IRsend            irsend;
      decode_results    ircode;
      
      
      #define           NO_PROG_MODE 0xFF
      byte              progModeId       = NO_PROG_MODE;
      
      MySensor gw;
      MyMessage msgIrReceive(CHILD_1, V_IR_RECEIVE);
      MyMessage msgIrRecord(CHILD_1, V_IR_RECORD); 
      
      void setup()  
      {  
        gw.begin(incomingMessage, NODEID);
      
        // Send the sketch version information to the gateway and Controller
        gw.sendSketchInfo("IR Rec/Playback", "1.0");
      
        // Register a sensors to gw. Use binary light for test purposes.
        gw.present(CHILD_1, S_IR);
      
        // Tell MYS Controller that we're NOT recording
        gw.send(msgIrRecord.set(0));
        
        Serial.println(F("Recall EEPROM settings"));
        recallEeprom(sizeof(StoredIRCodes), (byte *)&StoredIRCodes);
      
        // Start the ir receiver
        irrecv.enableIRIn(); 
        
        Serial.println(F("Init done..."));
      }
      
      void loop() 
      {
        gw.process();
        
        if (irrecv.decode(&ircode)) {
            dump(&ircode);
            if (progModeId != NO_PROG_MODE) {
               // If we are in PROG mode (Recording) store the new IR code and end PROG mode
               if (storeRCCode(progModeId)) {
                  Serial.print(F("Stored "));
                
                  // If sucessfull RC decode and storage --> also update the EEPROM
                  storeEeprom(sizeof(StoredIRCodes), (byte *)&StoredIRCodes);
                  progModeId = NO_PROG_MODE;
                 
                  // Tell MYS Controller that we're done recording
                  gw.send(msgIrRecord.set(0));
               }
            } else {
               // If we are in Playback mode just tell the MYS Controll we did receive an IR code
               if (ircode.decode_type != UNKNOWN) {
                   if (ircode.value != REPEAT) {
                     // Look if we found a stored preset 0 => not found
                     byte num = lookUpPresetCode(&ircode);
                     if (num) {
                         // Send IR decode result to the MYS Controller
                         Serial.print(F("Found code for preset #"));
                         Serial.println(num);
                         gw.send(msgIrReceive.set(num));
                     }
                   }
               }
          }
          // Wait a while before receive next IR-code
          delay(500);
          
          // Start receiving again
          irrecv.resume();
        }
      }
      
      void incomingMessage(const MyMessage &message) {
          //Serial.print(F("New message: "));
          //Serial.println(message.type);
         
         if (message.type == V_IR_RECORD) { // IR_RECORD V_VAR1
            // Get IR record requets for index : paramvalue
            progModeId = message.getByte() % MAX_IR_CODES;
            
            // Tell MYS Controller that we're now in recording mode
            gw.send(msgIrRecord.set(1));
            
            Serial.print(F("Record new IR for: "));
            Serial.println(progModeId);
         }
        
         if (message.type == V_IR_SEND) {
            // Send an IR code from offset: paramvalue - no check for legal value
            Serial.print(F("Send IR preset: "));
            Serial.print(message.getByte());
            sendRCCode(message.getByte() % MAX_IR_CODES);
         }
      
         // Start receiving ir again...
         irrecv.enableIRIn(); 
      }
      
      
      byte lookUpPresetCode (decode_results *ircode)
      {
          for (byte index = 0; index < MAX_IR_CODES; index++)
          {
            if ( StoredIRCodes[index].code.type  == ircode->decode_type &&
                 StoredIRCodes[index].code.value == ircode->value       &&
                 StoredIRCodes[index].code.len   == ircode->bits)      {
                // The preset number starts with 1 so the last is stored as 0 -> fix this when looking up the correct index
                return (index == 0) ? MAX_IR_CODES : index;
            }  
          }
          // not found so return 0
          return 0;
      }
          
      // Stores the code for later playback
      bool storeRCCode(byte index) {
      
        if (ircode.decode_type == UNKNOWN) {
      #ifdef IR_SUPPORT_UNKNOWN_CODES  
            Serial.println(F("Received unknown code, saving as raw"));
            // To store raw codes:
            // Drop first value (gap)
            // As of v1.3 of IRLib global values are already in microseconds rather than ticks
            // They have also been adjusted for overreporting/underreporting of marks and spaces
            byte rawCount = min(ircode.rawlen - 1, MY_RAWBUF);
            for (int i = 1; i <= rawCount; i++) {
              StoredIRCodes[index].raw.codes[i - 1] = ircode.rawbuf[i]; // Drop the first value
            };
            return true;
      #else 
            return false;
          }
      #endif
      
        if (ircode.value == REPEAT) {
            // Don't record a NEC repeat value as that's useless.
            Serial.println(F("repeat; ignoring."));
            return false;
         }
         StoredIRCodes[index].code.type      = ircode.decode_type;
         StoredIRCodes[index].code.value     = ircode.value;
         StoredIRCodes[index].code.address   = ircode.address;      // Used by Panasonic & Sharp [16-bits]
         StoredIRCodes[index].code.len       = ircode.bits;
         Serial.print(F(" value: 0x"));
         Serial.println(ircode.value, HEX);
         return true;
      }
      
      void sendRCCode(byte index) {
      
      #ifdef IR_SUPPORT_UNKNOWN_CODES  
         if(StoredIRCodes[index].code.type == UNKNOWN) {
            // Assume 38 KHz
            irsend.sendRaw(StoredIRCodes[index].raw.codes, StoredIRCodes[index].raw.count, 38);
            Serial.println(F("Sent raw"));
            return;
         }
      #endif
      
         Serial.print(F(" - sent "));
         Serial.print(Type2String(StoredIRCodes[index].code.type));
         if (StoredIRCodes[index].code.type == RC5) {
             // For RC5 and RC6 there is a toggle bit for each succesor IR code sent alway toggle this bit
             StoredIRCodes[index].code.value ^= 0x0800;
             irsend.sendRC5(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len);
          } 
          else if (StoredIRCodes[index].code.type == RC6) {
             // For RC5 and RC6 there is a toggle bit for each succesor IR code sent alway toggle this bit
             StoredIRCodes[index].code.value ^= 0x10000;
             irsend.sendRC6(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len);
         }
         else if (StoredIRCodes[index].code.type == NEC) {
             irsend.sendNEC(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len);
          } 
          else if (StoredIRCodes[index].code.type == SONY) {
             irsend.sendSony(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len);
          } 
          else if (StoredIRCodes[index].code.type == PANASONIC) {
             irsend.sendPanasonic(StoredIRCodes[index].code.address, StoredIRCodes[index].code.value);
             Serial.print(AddrTxt);
             Serial.println(StoredIRCodes[index].code.address, HEX);
          }
          else if (StoredIRCodes[index].code.type == JVC) {
             irsend.sendJVC(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len, false);
          }
          else if (StoredIRCodes[index].code.type == SAMSUNG) {
             irsend.sendSAMSUNG(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len);
          }
          else if (StoredIRCodes[index].code.type == WHYNTER) {
             irsend.sendWhynter(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len);
          }
          else if (StoredIRCodes[index].code.type == AIWA_RC_T501) {
             irsend.sendAiwaRCT501(StoredIRCodes[index].code.value);
          }
          else if (StoredIRCodes[index].code.type == LG || StoredIRCodes[index].code.type == SANYO || StoredIRCodes[index].code.type == MITSUBISHI) {
             Serial.println(NATxt);
             return;
          }
          else if (StoredIRCodes[index].code.type == DISH) {
             irsend.sendDISH(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len);
          }
          else if (StoredIRCodes[index].code.type == SHARP) {
             irsend.sendSharp(StoredIRCodes[index].code.address, StoredIRCodes[index].code.value);
             Serial.print(AddrTxt);
             Serial.println(StoredIRCodes[index].code.address, HEX);
          }
          else if (StoredIRCodes[index].code.type == DENON) {
             irsend.sendDenon(StoredIRCodes[index].code.value, StoredIRCodes[index].code.len);
          }
          else {
            // No valid IR type, found it does not make sense to broadcast
            Serial.println(NATxt);
            return; 
          }
          Serial.print(" ");
          Serial.println(StoredIRCodes[index].code.value, HEX);
      }    
      
      // Dumps out the decode_results structure.
      void dump(decode_results *results) {
          int count = results->rawlen;
          
          Serial.print(F("Received : "));
          Serial.print(results->decode_type, DEC);
          Serial.print(F(" "));
          Serial.print(Type2String(results->decode_type));
        
          if (results->decode_type == PANASONIC) {	
            Serial.print(AddrTxt);
            Serial.print(results->address,HEX);
            Serial.print(ValueTxt);
          }
          Serial.print(F(" "));
          Serial.print(results->value, HEX);
          Serial.print(F(" ("));
          Serial.print(results->bits, DEC);
          Serial.println(F(" bits)"));
        
          if (results->decode_type == UNKNOWN) {
            Serial.print(F("Raw ("));
            Serial.print(count, DEC);
            Serial.print(F("): "));
        
            for (int i = 0; i < count; i++) {
              if ((i % 2) == 1) {
                Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
              } 
              else {
                Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
              }
              Serial.print(" ");
            }
            Serial.println("");
          }
      }
      
      // Store IR record struct in EEPROM   
      void storeEeprom(byte len, byte *buf)
      {
          gw.saveState(0, len);
          for (byte i = 1; i < min(len, 100); i++, buf++)
          {
             gw.saveState(i, *buf);
          }
      }
      
      void recallEeprom(byte len, byte *buf)
      {
          if (gw.loadState(0) != len)
          {
             Serial.print(F("Corrupt EEPROM preset values and Clear EEPROM"));
             for (byte i = 1; i < min(len, 100); i++, buf++)
             {
                 *buf = 0;
                 storeEeprom(len, buf);
             }
             return;
          }
          for (byte i = 1; i < min(len, 100); i++, buf++)
          {
             *buf = gw.loadState(i);
          }
      }   
          
      
      posted in My Project
      BartE
      BartE
    • Running ATmega328P on internal 8MHz clock

      Playing around a little bit with GertSanders 50 by 30 mm PCB i was wondering if this board also could run without the external clock (8MHz crystal). Saving not only a couple of components but even better save battery lifetime. It appears the ATmega328 uses less power when running on the internal clock.

      It turned out to be a bigger puzzle than expected i was not able to find a straight answer nor a ready-mate solution. Fortunately i did found a couple partial solution and will try describe the way it worked out for my setup.

      It all starts with a bare ATmega328P chip, they are sold in basically 2 flavors. One with-out a bootloader (see Wikipedia) (or with a non Arduino) they are programmed to run on the 1 MHz internal clock. The second flavor is shipped with a pre-programmed Arduino R3 bootloader these will expect a 16 MHz external clock, (but an 8 MHz crystal will do).

      The clock settings are made by so-called fuses, a better name would be internal dip-switches since a fuse sounds like one-time only programming , while the ATmega's fuses can be re-programmed over and over again. So for both flavors we need change theses fuses and for the first flavor we also need to program a bootloader.

      On the Arduino website we can read how to program a bootloader by connecting it to an Arduio UNO (see here) BUT in this case the programming it selves did not worked out. So wiring is OK the program sequence not:

      • For the empty 328p's this wiring will do (so no Crystal) https://www.arduino.cc/en/uploads/Tutorial/SimpleBreadboardAVR.png

      • For the one with an bootloader one needs to wire the 328P like this: https://www.arduino.cc/en/uploads/Tutorial/BreadboardAVR.png

      A better way to program the Arduino is using the sketch from Bill Westfield which can be found here: https://github.com/WestfW/OptiLoader So download this sketch into the Arduino UNO and when wired liked described above the new Atmega is programmed with a fresh bootloader.

      The last step is the set the correct fuses so the interval 8 MHz clock is used. This turned-out to be not so easy to figure out . There are 3 fuse bytes which need to be set. The "Low", "High" and "Extented" , in the end i did run this page: http://www.engbedded.com/fusecalc/. Where you can selected the appropriate configuration and the site will "calculate" the correct byte's (and vice versa).

      The setting which does work for me are:

      • Low := 0xE2
      • High := 0xDE
      • Ext. := 0xFD

      To set these fuse bytes in the Atmega one needs to change Bill's OptiLoader script around line 730 you can find
      this peace of code:

      const image_t PROGMEM image_328p = {
        {
          "optiboot_atmega328.hex"    }
        ,
        {
          "atmega328P"    }
        ,
        0x950F,				/* Signature bytes for 328P */
        {
           0x3F,0xFF,0xDE,0x05,0   }
        ,
        {
          0x2F,0,0,0,0     }
      

      Once change to this the correct fuse byte's are used

      const image_t PROGMEM image_328p = {
        {
          "optiboot_atmega328.hex"    }
        ,
        {
          "atmega328P"    }
        ,
        0x950F,				/* Signature bytes for 328P */
        {
          // 16 MHz external crystal
      //    0x3F,0xFF,0xDE,0x05,0   
          // 8 MHz internal crystal
            0x3F,0xE2,0xDE,0xFD,0  
      }
        ,
        {
          0x2F,0,0,0,0   
        }
      

      So in short:

      • Connect your new Atmega to an Arduino UNO
      • Download Bill Westfield skecth WITH fuse modifaction into the UNO
      • Give a reset and look at your terminal if the bootloader and fuse where set correctly

      Once the correct bootloader is in. You can place the ATmega328 in GertSanders PCB and program a sketch in in with these type of FTDI USB serial convertors: http://www.ebay.com/itm/320907184616?rmvSB=true.
      Set the Ardiuno IDE to:

      • Tools -> Board -> Arduino Pro or Pro Mini
      • Tools -> Processor -> ATmega328 (3.3V 8 MHz)
      • Tools -> Board -> ArduinoISP

      And have fun with it...

      posted in Hardware
      BartE
      BartE
    • Single button operated Led Strip Dimmer

      Since i wanted to integrate a dimming led strip in my existing house electrical system i did create the following projected.

      It had to:

      • fit in my electrical wiring (so need to pull additional wires)
      • single button operation (standard house switch)
      • full MySensors dimming and control features

      During development i discovered that (in my situation) the standard LED strip dimmer did not reach 12 volt @ 100% dim level (digitalWrite(pin, 255)) so a had to added a extra NPN transistor to reach the full 12 volt an thus maximum light. "Down site" of this extra transistor an inverted dim control so digitalWrite(pin, 255) will give no light and digitalWrite(pin, 0) 100%.

      To make use of the standard in-wall switch i added a relay with a 230v coil controlling a 5 volt input pin a to signal the Arduino

      This is the electrical prototype scheme:

      LedStripSwitch.png

      It operates like this:

      • Just toggling the switch will light the LED-(strip) smooth to 100% level or back to 0% when turning the light off.
      • By a short ON-OFF switch-pulse the LED will dim to the last set dim level when it was OFF or dim to 0% when the LED was on.
      • Setting a new target dim level can be done by keeping the switch on until it reaches the desired dim-level and the switch OFF again.
      • Now the LED will stay on keeping the dim level
      • In all situations your home automation controller will be informed on the changing situations and off course can override the switch situation

      This sketch controls 2 LED-(strips) but can be easily extended by adding a LEDS entry to the led array (on line 67) the amount of leds is limited by the amount of PWM pins on your Arduino this is 6 (pin#3,5,6, 9,10,11), but 3 of these PWN pins (9.10,11) are occupied by the radio (NRF24L01), were pin 9 of the radio can be remapped
      For the switch input both analog (Ax) and digital (Dx) pins can be used

      The dim level can be set linear i.s.o. logarithmic (for your eyes this will look more linear)

      /**
       * REVISION HISTORY
       * Version 1.0 - February 15, 2014 - Bruce Lacey
       * Version 1.1 - August 13, 2014 - Converted to 1.4 (hek) 
       * Version 1.2 - Januari 2016 - Bart Eversdijk
       *
       * DESCRIPTION
       * This sketch provides a Dimmable LED Light using PWM and based on Henrik Ekblad 
       * <henrik.ekblad@gmail.com> Vera Arduino Sensor project.  
       * Developed by Bruce Lacey, inspired by Hek's MySensor's example sketches.
       * 
       * The circuit uses a MOSFET for Pulse-Wave-Modulation to dim the attached LED or LED strip.  
       * The MOSFET Gate pin is connected to Arduino pin 3 (LED_PIN), the MOSFET Drain pin is connected
       * to the LED negative terminal and the MOSFET Source pin is connected to ground.  
       *
       * V1.2 Additions:
       * control by normal ON/OFF switch
       * The sketch is now optimized for integration in an existing house wiring situation, Where a standard light switch can be used to control
       * the dimmer. Just toggling the switch will light the LED-(strip) smooth to 100% level or back to 0% when turning the light off.
       * By a short ON-OFF switch-pulse the LED will dim to the last set dim level (when it was OFF) or dim to 0% when the LED was on.
       * Setting a new target dim level can be done by keeping the switch on until it reaches the desired dim-level and the switch OFF again. 
       * Now the LED will stay on keeping the dim level. 
       * In all situations your home automation controller will be informed on the changing situations and off course can override the switch situation 
       * 
       * This sketch controls 2 LED-(strips) but can be easily extended by adding a LEDS entry to the led array (on line 70)
       * The dim level can be set linear i.s.o. logarithmic (for your eyes this will look more linear)
       *
       * http://www.mysensors.org/build/dimmer
       */
      
      #include <MySensor.h> 
      #include <SPI.h>
      #include <Bounce2.h>
      #include <math.h>
      
      #define LED1_PIN    6  // Arduino pin attached to MOSFET Gate pin
      #define SW1_PIN     4
      #define LED2_PIN    3  // Arduino pin attached to MOSFET Gate pin
      #define SW2_PIN     2
      
      #define MYS_INIT_DELAY 500
      
      #define FADE_DELAY 10  // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim)
      enum DIMCURVES {
        DIM_LINEAR = 0,        // Normal linear curve
        DIM_LINEAR_INV,        // Inverted linear curve
        DIM_LOGARITHMIC,       // Normal logarithmic curve
        DIM_LOGARITHMIC_INV,   // Inverted logarithmic curve
        DIM_CUSTOM             // Define your own dimming curve
      };
      
      struct LEDS {
          int       currentLevel; // Current dim level
          int       toLevel;      // Level to dim to
          Bounce    debouncer;
          int       LedPin;
          int       SwitchPin;
          byte      switchValue;
          int       savedLevel;   // level to dim to when on is pressed
          int       switchCount;
          bool      ignoreNextSw; // if true ignore next OFF switch (was overriden by controller in ON state)
          DIMCURVES dimcurve;     // Set the dim curve mode (linear, logarithmic, inverted, custom) 
          MyMessage dimmerMsg;
          MyMessage lightMsg;
      };
      
      LEDS led[] = {
                {0, 0, Bounce(), LED1_PIN, SW1_PIN, 0, 100, 0, false, DIM_LINEAR_INV, MyMessage(0, V_DIMMER), MyMessage(0, V_LIGHT)},
                {0, 0, Bounce(), LED2_PIN, SW2_PIN, 0, 100, 0, false, DIM_CUSTOM,     MyMessage(1, V_DIMMER), MyMessage(1, V_LIGHT)} 
              };
      #define MAXLED (sizeof(led)/sizeof(LEDS))
      
      MySensor gw;
      
      /***
       * Dimmable LED initialization method
       */
      void setup()  
      { 
         // Switch off all leds
         for (byte id = 0; id < MAXLED; id++) {
             pinMode(led[id].LedPin, OUTPUT);
             setLedLevel(id);
         }
         
         gw.begin( incomingMessage );
        
         // Register the LED Dimmable Light with the gateway
         for (byte id = 0; id < MAXLED; id++) {
             pinMode(led[id].SwitchPin, INPUT);
             // Activate internal pull-up
             digitalWrite(led[id].SwitchPin, HIGH); 
              
             gw.present( id, S_DIMMER );
             delay( MYS_INIT_DELAY );
      
             // Pull the gateway's current dim level - restore light level upon sendor node power-up
             gw.request( id, V_DIMMER );
             delay( MYS_INIT_DELAY );
             
             // After setting up the button, setup debouncer
             led[id].debouncer.attach(led[id].SwitchPin);
             led[id].debouncer.interval(5);
         }
          
         gw.sendSketchInfo("1.2", "LedStripSwitch");
      }
      
      /***
       *  Dimmable LED main processing loop 
       */
      void loop() 
      {
           gw.process();
           
           for (byte id = 0; id < MAXLED; id++) {
             // If target level is not reached fade a little bit more
              if (led[id].currentLevel != led[id].toLevel)  {
                 led[id].currentLevel += ((led[id].toLevel - led[id].currentLevel ) < 0 ? -1 : 1);
                 setLedLevel(id);
              }
      
              // Check debounced button  
              led[id].debouncer.update();
              byte switchValue = led[id].debouncer.read() ? 0 : 1; // Inverted signal 
              
              // Button change detected
              if (led[id].switchValue != switchValue) {
                 Serial.print (F("Switch "));
                 Serial.println (switchValue);
                 led[id].switchValue = switchValue;
                 
                 // If key released switch on when off or off when on --> when we where fading (above 100 steps) this is the end state
                 // When we just left the button (> 500) we now turning the lights off again
                 if (!switchValue && !led[id].ignoreNextSw) {
                    if (led[id].switchCount <= 100 || led[id].switchCount > 500) {
                        led[id].toLevel = (led[id].currentLevel ? 0 : led[id].savedLevel);
                    } else {
                        led[id].savedLevel = led[id].toLevel; // Store new saved level
                    }
                    
                    // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
                    gw.send(led[id].lightMsg.set(led[id].toLevel > 0 ? 1 : 0));
                    gw.send(led[id].dimmerMsg.set(led[id].toLevel) );
                 }
                 led[id].ignoreNextSw = false;
                 led[id].switchCount = 0;
              } else if (switchValue && led[id].switchCount <= 500) {
                 // Keep counting until we reached 500 (@ 500 we asume we are in switch ON / OFF mode)
                 led[id].switchCount++;
                 
                 // So this in not just a switch on (or off) but a new target led level key press
                 if (led[id].switchCount > 100) {
                    // Smooth led level increment, until the user found his/here desired dim lever
                    if ((led[id].switchCount % 3) == 0) {
                        // Stop increasing led level @ 100%
                        if (led[id].currentLevel < 100) {
                            if (led[id].currentLevel == 99) {
                                // Inform the gateway we've reached 100%
                                gw.send(led[id].lightMsg.set(1));
                                gw.send(led[id].dimmerMsg.set(100));
                            }
                            led[id].currentLevel++;
                            led[id].toLevel = led[id].currentLevel;
                            setLedLevel(id);
                        } 
                    }
                 }
              } 
           }  
           
           // Wait FADE_DELAY ms to smooth the dim level adjustments
           gw.wait(FADE_DELAY);
      }
      
      void incomingMessage(const MyMessage &message) {
         if (message.type == V_LIGHT || message.type == V_DIMMER) {
           byte id = (message.sensor % MAXLED);
            
            // Retrieve the power or dim level from the incoming request message
            // if this is a V_LIGHT variable update [0 == off, 1 == on] use savedLevel
            int requestedLevel = ( message.type == V_LIGHT ? led[id].savedLevel * atoi( message.data )  : atoi( message.data ) );
            if (requestedLevel > 0) {
               // Store as lastLevel
               led[id].savedLevel = requestedLevel;
            }
            // Make sure the new level is between 0 - 100     
            led[id].toLevel = (requestedLevel >= 0 ? min(requestedLevel, 100) : 0);
            
            Serial.print(F("Changing node: "));
            Serial.print( id );
            Serial.print(F(", from: "));
            Serial.print( led[id].currentLevel );
            Serial.print(F("%, to: ")); 
            Serial.print( requestedLevel );
            Serial.println(F("%")); 
            
            // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value...
            gw.send(led[id].lightMsg.set(requestedLevel > 0 ? 1 : 0));
            gw.send(led[id].dimmerMsg.set(requestedLevel) );
            
            // Ignore next OFF switch when switch is ON and controller switches LED to OFF state)
            led[id].ignoreNextSw = (led[id].toLevel == 0 && led[id].SwitchPin);
         }
      }
      
      
      void setLedLevel(byte id)
      {
         // Convert  level 0% - 100% to logathimic OR linear PWM range of 0 to 255 
         switch (led[id].dimcurve)
         {
            case DIM_LINEAR:
               // Normal linear curve
               analogWrite(led[id].LedPin, (int)(led[id].currentLevel * 2.5));
               break;
               
            case DIM_LINEAR_INV:
               // Inverted linear curve
               analogWrite(led[id].LedPin, 255 - (int)(led[id].currentLevel * 2.5));
               break;
               
            case DIM_LOGARITHMIC:
               // Normal logarithmic curve
               analogWrite(led[id].LedPin, fscale( 0, 100, 0, 255, led[id].currentLevel, -2));
               break;
      
            case DIM_LOGARITHMIC_INV:
               // Inverted logarithmic curve
               analogWrite(led[id].LedPin, 255 - fscale( 0, 100, 0, 255, led[id].currentLevel, -2));
               break;
               
            case DIM_CUSTOM:
              analogWrite(led[id].LedPin, 255 - led[id].currentLevel);
              break;
         }
      }
      
      /* fscale
       Floating Point Autoscale Function V0.1
       Paul Badger 2007
       Modified from code by Greg Shakar
       */
      float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve) 
      {
        float   OriginalRange = 0;
        float   NewRange = 0;
        float   zeroRefCurVal = 0;
        float   normalizedCurVal = 0;
        float   rangedValue = 0;
        boolean invFlag = 0;
      
       // condition curve parameter
        // limit range
       if (curve > 10) curve = 10;
        if (curve < -10) curve = -10;
      
        curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output 
        curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function
      
        // Check for out of range inputValues
        if (inputValue < originalMin) {
          inputValue = originalMin;
        }
        if (inputValue > originalMax) {
          inputValue = originalMax;
        }
      
        // Zero Refference the values
        OriginalRange = originalMax - originalMin;
      
        if (newEnd > newBegin){ 
          NewRange = newEnd - newBegin;
        } else {
          NewRange = newBegin - newEnd; 
          invFlag = 1;
        }
      
        zeroRefCurVal = inputValue - originalMin;
        normalizedCurVal  =  zeroRefCurVal / OriginalRange;   // normalize to 0 - 1 float
      
        // Check for originalMin > originalMax  - the math for all other cases i.e. negative numbers seems to work out fine 
        if (originalMin > originalMax ) {
          return 0;
        }
      
        if (invFlag == 0) {
          rangedValue =  (pow(normalizedCurVal, curve) * NewRange) + newBegin;
        } else { // invert the ranges   
          rangedValue =  newBegin - (pow(normalizedCurVal, curve) * NewRange); 
        }
      
        return rangedValue;
      }
      
      posted in My Project
      BartE
      BartE
    • RE: 💬 MySensors @Eindhoven Maker Fair 2017 2-3 September

      oke some pics..

      Queue to get in 🙂
      0_1504359522596_IMG_7507.JPG

      The booth
      0_1504359562210_IMG_7509.JPG

      0_1504359650015_IMG_7510.JPG
      0_1504359679592_IMG_7512.JPG

      posted in Announcements
      BartE
      BartE
    • RE: Eprom erase Jumper

      HI @kr0815 , what you can do is add a piece of code which checks for a jumper presence on start-up if so just erase your EEPROM.

      An input pin will become LOW when the jumper connects this pin to GND and will become HIGH when the jumper is removed (stable high by activating the interval pull up resistor)

      This jumper check code can be something like this:

          pinMode(CLEAR_EEPROM_JUMPER, INPUT);           // set pin to input
          digitalWrite(CLEAR_EEPROM_JUMPER, HIGH);       // turn on internal pull up resistors
          delay(50);                                     // Wait to stabilize the input pin
          // If jumper is placed and thus the input pin is LOW a clean EEPROM is required
          if (digitalRead(CLEAR_EEPROM_JUMPER) == LOW) {
              Serial.begin(BAUD_RATE);
              Serial.println(F("Clearing EEPROM. Please wait..."));
              for (int i=0;i<512;i++) {
                  EEPROM.write(i, 0xff);
              }
              Serial.println(F("Clearing done. Continue with normal init..."));
          }
      

      A very simple plug in would look something like this:

      #include <MySensor.h>
      #include <SPI.h>
      #include <EEPROM.h>  
      
      // Clear EEPROM jumper: when placed this pin should be connected to GND 
      #define CLEAR_EEPROM_JUMPER  6
      
      MySensor gw;
      
      void setup()  
      { 
          pinMode(CLEAR_EEPROM_JUMPER, INPUT);           // set pin to input
          digitalWrite(CLEAR_EEPROM_JUMPER, HIGH);       // turn on internal pull up resistors
          delay(50);                                     // Wait to stabalize the input pin
          // If jumper is placed and thus the input pin is LOW a clean EEPROM is required
          if (digitalRead(CLEAR_EEPROM_JUMPER) == LOW) {
              Serial.begin(BAUD_RATE);
              Serial.println(F("Clearing EEPROM. Please wait..."));
              for (int i=0;i<512;i++) {
                  EEPROM.write(i, 0xff);
              }
              Serial.println(F("Clearing done. Continue with normal init..."));
          }
          
          // place normal init here
          gw.begin();
      }
      
      void loop()      
      { 
          // Normal sensor stuff here
          gw.process();
      } 
      

      Just add this check to all your plugin code

      posted in Feature Requests
      BartE
      BartE
    • Combined MySensor Gateway with 433Mhz transmitter (HomeEasy/Klik-Aan-Klik-uit)

      In Holland there is an affordable popular brand for home automation called Klik-aan-klik-uit. These module are also sold in other countries as different brands like HomeEasy, more can be found here There are several (Aurdio) projects which decode en encode this RF protocol.

      To be able to controll my HomeAutomation network with an Klik-aan-klik-uit (AYCT-104) remote controller i fitted my MySensor gateway with an RF 433Mhz receiver (and transmitter). The transmitter / receiver are of type : this type
      I used the decoding software from (Randy Simons http://randysimons.nl/) which i modified so it can receive both the new
      style and on style protocol messages. Read this thread for more background information.

      How to connect:

      • Take a standard MySensors gateway
      • And addtional connect the both the RF receiver and tansmitter ground and Vcc to the GND and 5V pins of your Ardiuno
      • Connect the RF receiver data pin to Arduino pin 2 (interrupt 0 pin)
      • Connect the RF transmitter data pin to Arduino pin 7

      The recieved RC commands are sent to my Vera controller next to the MySensor messages. These commands have this format "rf;<number>" to be able to distinguish between MySensor commands and HomeEasy command i changed the MySensor lua-core file.

      Other changes to the MySensor controller core are:

      • Each received command is shown on the inclusion count area, the see which command can be used
      • A scene controller is added on first inclusion, which can be use to activate scnenes where the scene number is the recieved command.
      • The settings tab of primary MySensor device has a number of field where devices (Light) can be controlled directly on RF reception. The first column is the Vera device ID, the second column the RF code the switch on the device, the third column the RF code to switch off the column

      Rf-gateway.jpg

      The arduino code:
      mySensorsRemoteGW.zip

      The modified MySensors Vera code:
      Vera_RFGateway.zip

      posted in My Project
      BartE
      BartE
    • My MySensors RGBW plug in has an init problem

      I've created a RGB(W) led strip MySensors controller which interacts with the RGB color wheel plug in from MiOS Marketplace.

      The problem i have with it is that the the Arduino plug in does not initialize with MiOS plug in as "slave" plug in.
      It is made by vosmont and can be found here and i've added MyS support (see below)

      If someone can help me by fixing the init problem it would be really nice, but so far.

      i did make a small work around (tested with UI5 Vera 3):
      1 make sure both Arduino and the MiOS RGB controller module are installed.
      2 start MySensors inclusion
      3 reset MySensors RGB module
      4 Two devices will (should) be detected and appear. (a MYS controller and a RGB color wheel)
      5 Remember the RBV modules 'altid' (wrench-icon, Advanced-tab), this looks like "6;1"
      6 Remember the Device ID of the MYS Arduindo master plug in
      7 Now delete the RGB color wheel (trash can icon)
      8 Create a new device (APPS -> Develop Apps -> Create device)
      9 Description field: <give a usefull name> like RGB strip
      Upnp Device Filename field : D_RGBController1.xml
      No parent device !!!
      10 Press the Create device button
      11 Press the reload button, wait for the system becomes stable
      12 Change the setting of te RGB controller (wrench-icon, Settings-tab)
      13 Select: MySensors RGBW
      Arduino plugin Id: <enter ID remembered and step 6>
      RGB Node altid: <enter ID remembered and step 5>
      14 Press save button
      15 Now the color wheel can be used

      rgbcolor.png

      To be able to control MyS RGB modules the following coded is added to L_RGBController1.lua after line 1004 (before Color transition management)

      -- MySensor RGB(W)
      RGBDeviceTypes["MYS-RGBW"] = {
      	getParameters = function (lul_device)
      		return {
      			name = "MySensors RGBW",
      			settings = {
      				{ variable = "ArduinoId", name = "Arduino plugin Id", type = "string" },
      				{ variable = "RadioId",   name = "RGB Node altid",    type = "string" }
      			}
      		}
      	end,
      
      	getColorChannelNames = function (lul_device)
      		return {"red", "green", "blue", "warmWhite"}
      	end,
      
      	getAnimationProgramNames = function()
      		return {
      			"Rainbow slow",
      			"Rainbow medium",
      			"Rainbow fast",
      			"Random slow colors",
      			"Random medium colors",
      			"Random fast colors",
      			"RGB fade slow colors",
      			"RGB fade medium colors",
      			"RGB fade fast colors",
      			"Multicolor fade slow colors",
      			"Multicolor fade medium colors",
      			"Multicolor fade fast colors",
      			"Current color flash slow colors",
      			"Current color flash medium colors",
      			"Current color flash fast colors",
      		}
      	end,
      
      	init = function (lul_device)
      		debug("MYS-RGBW.init", "Init for device #" .. tostring(lul_device))
      		pluginParams.rgbArduinoId = tonumber(getVariableOrInit(lul_device, SID.RGB_CONTROLLER, "ArduinoId", ""))
      		pluginParams.rgbRadioId = getVariableOrInit(lul_device, SID.RGB_CONTROLLER, "RadioId", "")
      		return true
      	end,
      
      	setStatus = function (lul_device, newTargetValue)
      		debug("MYS.setStatus", "Set status '" .. tostring(newTargetValue) .. "' for device #" .. tostring(lul_device))
      		if (tostring(newTargetValue) == "1") then
      			debug("MYS.setStatus", "Switches on ")
      			local formerColor = luup.variable_get(SID.RGB_CONTROLLER, "Color", lul_device):gsub("#","")
      			luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "RGBW", value = formerColor, radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId)
      			luup.variable_set(SID.SWITCH, "Status", "1", lul_device)
      		else
      			debug("MYS.setStatus", "Switches off")
                              luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "LIGHT", value = "0", radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId)
      			luup.variable_set(SID.SWITCH, "Status", "0", lul_device)
      		end
      
      	end,
      
      	setColor = function (lul_device, color)
      		colorString = tostring(color)
      		debug("MYS.setColor", "Set RGBW color #" .. colorString .. " for device #" .. tostring(lul_device))
                      luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "RGBW", value = colorString, radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId)
      	end,
      
      	startAnimationProgram = function (lul_device, programId, programName)
      		if ((programName ~= nil) and (programName ~= "")) then
      			--debug("MYS.startAnimationProgram", "Start animation program '" .. programName .. "'")
      			mode = 0
      			if string.match(programName, "Random") then
      				mode = 0x01
      			end
      			if string.match(programName, "RGB fade") then
      				mode = 0x02	
      			end
      			if string.match(programName, "Multicolor fade") then
      				mode = 0x03	
      			end
      			if string.match(programName, "Current color flash") then
      				mode = 0x04
      			end
      			if string.match(programName, "slow") then
      				mode = 0x10 + mode
      			end
      			if string.match(programName, "medium") then
      				mode = 0x20 + mode
      			end
      			if string.match(programName, "fast") then
      				mode = 0x30 + mode
      			end
      			debug("MYS.startAnimationProgram", "Start animation program '" .. programName .. "' " .. tostring(mode))
      			luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "VAR_1", value = tostring(mode), radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId)
      		else
      			debug("MYS.startAnimationProgram", "Stop animation program")
      			luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {variableId = "VAR_1", value = "00", radioId = pluginParams.rgbRadioId}, pluginParams.rgbArduinoId)
      			setColorTarget(lul_device, "")
      		end
      	end
      }
      
      

      And this is the MyS RGB color strip plugin

      // RBG led strip plug in.
      // by Bart Eversdijk (c) 2015.
      #include <MySensor.h>
      #include <SPI.h>
      
      // If not defined RGB is used otherwise RGBW
      #define RGBW 1
      
      #define RED   3  // Arduino PWM pin for Red
      #define GREEN 5 // Arduino PWM pin for Green
      #define BLUE  6  // Arduino PWM pin for Blue
      #define WHITE 7  // Arduino PWM pin for White (ilumination)
      
      
      enum ANIMATIOMODES {RAINBOW=0,RANDONMIZE,FADERGB,FADEMULTICOLR,FLASHCOLOR,LAST_PROGRAM};
      
      byte FADE_RGB_COLOR_MODES[]   = {0b0010,0b0011,0b0100,0b0101,0b1000,0b1001, 0xFF};
      byte FADE_MULTI_COLOR_MODES[] = {0b0010,0b0011,0b0110,0b0111,0b0100,0b0101,0b1100,0b1101,0b1000,0b1001,0b1010,0b1011,0xFF};
      
      #ifdef RGBW
        #define NODENAME "RGBW node"
        #define NODETYPE S_RGBW_LIGHT
        byte rgb_pins[] = {RED, GREEN, BLUE, WHITE};
      #else
        #define NODENAME "RGB node"
        #define NODETYPE S_RGB_LIGHT
        byte rgb_pins[]   = {RED, GREEN, BLUE};
      #endif
      
      byte ledOffValues[] = {0, 0, 0, 0};
      byte rgb_values[]   = {0, 0, 0, 0};
      
      #define NODEID 2  // Assigning the node id
      #define SUBID  1  // sensor number needed in the custom devices set up
      
      void incomingMessage(const MyMessage &message);
      #define NUM_OF_COLORS sizeof(rgb_pins)
      int speedtable[] = { 0, 100, 50, 2 };
      #define NUM_OF_SPEEDS sizeof(speedtable)
      
      struct
      {
         byte values[4];
         byte speedsetting;
         byte mode;
         bool status;
      } rgb = { {0,0,0,0}, 0, RAINBOW, false};
      
      bool    flashOn      = true;
      int     syscounter   = 0;
      int     lastUpdate   = 0;
      bool    newSetting   = false;
      
      MySensor gw; 
      
      void setup()
      {
          // Initialize library and add callback for incoming messages
          gw.begin(incomingMessage, AUTO /*NODEID*/);
          // Send the sketch version information to the gateway and Controller
          gw.sendSketchInfo(NODENAME, "1.1");
          // Register the sensor to gw
          gw.present(SUBID, NODETYPE);
      
          // Set the rgb(w) pins in output mode
          for (int i = 0; i < NUM_OF_COLORS; i++) {
              pinMode(rgb_pins[i], OUTPUT);
          }
          recallEeprom();
          setLedValues(rgb.values, true);
          
          Serial.println("Init done");
      }
      
      void loop()
      {
          // Alway process incoming messages whenever possible
          gw.process();
      
          if (speedtable[rgb.speedsetting] > 0) {
              if ((syscounter % speedtable[rgb.speedsetting]) == 0) {
                 switch (rgb.mode)
                 {
                     case RAINBOW:
                       animateRainbowStep();
                       break;
      
                     case FADERGB:
                       animateFadeColorStep(FADE_RGB_COLOR_MODES);
                       break;
      
                     case FADEMULTICOLR:
                       animateFadeColorStep(FADE_MULTI_COLOR_MODES);
                       break;
                   
                    case FLASHCOLOR:
                       setLedValues(flashOn ? ledOffValues : rgb.values, false);
                       flashOn = !flashOn;
                       break;
                                   
                     case RANDONMIZE:
                       long number = random(0, 0xFFFFFF);
                       rgb_values[0] = number >> 16 & 0xFF ;
                       rgb_values[1] = number >> 8 & 0xFF ;
                       rgb_values[2] = number & 0xFF;
                       setLedValues(rgb_values, false);
                       break;
                 }
              }
              delay(rgb.mode == RANDONMIZE || rgb.mode == FLASHCOLOR ? 50 : 1);
          }
          if (newSetting && (lastUpdate + 30000 < syscounter)) {   
              // Wait for a couple of seconds be fore actual storing the current setting in to EEPROM
              // This will save the EEPROM's life time, when playing around with colors
              Serial.println(" Store EERPOM");
              storeEeprom();
              newSetting = false;
          } 
          delay(1);
          syscounter++;
      }
      
      void animateRainbowStep()
      {    
          static float counter = 0;
          float        pi      = 3.14159; 
          counter++;
          rgb_values[0] = map(sin(counter/100         )*1000,-1000,1000,0,255);
          rgb_values[1] = map(sin(counter/100 + pi*2/3)*1000,-1000,1000,0,255);
          rgb_values[2] = map(sin(counter/100 + pi*4/3)*1000,-1000,1000,0,255);
          setLedValues(rgb_values, false);
      }
      
      void animateFadeColorStep(byte *modes)
      {    
          static int modecnt = 0;
          if (updateRGBValues(modes[modecnt] >> 1, (modes[modecnt] & 0x1) == 0x1)) { 
              modecnt = (modes[modecnt+1] == 0xFF ? 0 : modecnt + 1);
          }
      }
      
      bool updateRGBValues(byte mode, bool down)
      {
          bool endReached = false;
          for (byte i = 0; i < 3; i++) {
              if (((mode >> i) & 0x1) == 0x1) {
                 rgb_values[i] += (down ? -1 : 1);
                 endReached    |= (down && (rgb_values[i] == 0x00)) || (!down && (rgb_values[i] == 0xFF));
              }
          }
          setLedValues(rgb_values, false);
          return endReached;
      }
      
      
      void incomingMessage(const MyMessage &message) {
          if (message.type == V_RGB || message.type == V_RGBW) {
      	// starting to process the hex code
              String hexstring = message.getString();
      
              long number;
      #ifdef RGBW
              char white[3];
              white[0] = hexstring[6];
              white[1] = hexstring[7];
              white[2] = 0;
              number = (long) strtol( &white[0], NULL, 16);
              rgb.values[3] = number & 0xFF;
      #endif        
              hexstring[6] = 0;
              number = (long) strtol( &hexstring[0], NULL, 16);
              rgb.values[0] = number >> 16 & 0xFF ;
              rgb.values[1] = number >> 8 & 0xFF ;
              rgb.values[2] = number & 0xFF;
              
              rgb.speedsetting = 0;
              setLedValues(rgb.values, true);
              lastUpdate = syscounter;
              newSetting = true;
          }
          
          if (message.type == V_STATUS) {
            if (message.getBool()) {
                Serial.println("ON: Switch to last known color values");
                setLedValues(rgb_values, true);
            } else {
               Serial.println("OFF: Switch colors off");
               setLedValues(ledOffValues, true);
            }
            rgb.speedsetting = 0;
            rgb.status = message.getBool();
            lastUpdate = syscounter;
            newSetting = true;
          }
          
          if (message.type == V_VAR1) {
             Serial.println("Set speed and program value"); 
             byte newsetting = message.getByte();
             rgb.speedsetting = (newsetting >> 4) & 0x0F;
             byte newmode = newsetting & 0x0F;
      
             if (newmode != rgb.mode) {
                 for (byte i = 0; i < NUM_OF_COLORS; i++) {
                     rgb_values[i] = 0;
                 }
                 rgb.mode = newmode;
             }
             if (rgb.speedsetting > 0) {
               rgb.status = true;
             }
             lastUpdate = syscounter;
             newSetting = true;
            
             Serial.print("Data 0x");
             Serial.print(newsetting, HEX);
             Serial.print(" speed:");
             Serial.print(rgb.speedsetting);
             Serial.print(" mode:");
             Serial.println(rgb.mode);
          }
      }
      
      void setLedValues(byte *rgb, bool show)
      {
          for (int i = 0; i < NUM_OF_COLORS; i++) {
              analogWrite(rgb_pins[i], rgb[i]);
          }  
       
          if (show) {
            Serial.print("Red: " );
            Serial.print(rgb[0], HEX);
            Serial.print("  Green: " );
            Serial.print(rgb[1], HEX);
            Serial.print("  Blue: " );
            Serial.print(rgb[2], HEX);
       #ifdef RGBW
              Serial.print("  White is " );
              Serial.print(rgb[3], HEX);
       #endif
            Serial.println();
          }
      }
      
      void storeEeprom()
      {
          byte address = 0;
          byte *p = (byte *)&(rgb);
          for (byte i = 0; i < sizeof(rgb); i++) {
             gw.saveState(address++, p[i]);
          }
      }
      
      void recallEeprom()
      {
          byte address = 0;
          byte *p = (byte *)&(rgb);
          for (byte i = 0; i < sizeof(rgb); i++) {
             p[i] = gw.loadState(address++);
          }
      }
      

      Adding a reference to the MiOS forum about this plug in:
      http://forum.micasaverde.com/index.php/topic,32613.0.html

      posted in Vera
      BartE
      BartE
    • RE: Looking for LED 7-segment cover plate

      @mfalkvidd thx for the tip i use the a eds bag with a semi transparent red foil

      @niccodemi the bezel shop you suggested does not ship bezel large enough and for the box i did use this box http://www.ebay.com/itm/201180688204

      This is the end result of my MySensor based clock radio
      (Unfortunately finished to late for the contest)

      0_1459280782340_clockradio.png

      posted in General Discussion
      BartE
      BartE
    • RE: How to find out if message was successfully delivered?

      Hi @arraWX

      When you set the ack boolean to true while sending a message the gateway will return the message with the ACK bit set.

      So you have to handle this message with code like this

      setup ()
      {
         ... do stuff
      
         gw.begin(incomingMessage, AUTO, true);
      
        ... do more stuff
      }
      
      
      void incomingMessage(const MyMessage &message) {
        if (message.isAck()) {
            Serial.println("This is an ack from gateway");
            if (message.sensor == YOUR_KWH_SENSOR_ID) {
                   toggleLed();
            }
        }
      }
      
      posted in Development
      BartE
      BartE
    • RE: IR Record and Playback module

      Adding some Vera screenshots
      upload-89cc6ee3-ce20-44d0-a53c-79305c023d6c
      upload-1d15bc07-5e6d-46ce-87df-cae8adbb5159

      posted in My Project
      BartE
      BartE
    • RE: Looking for LED 7-segment cover plate

      @mfalkvidd said:

      Very cool, I love the big red button. Where did you find it?

      I did found it i my box with electronic parts 🙂 i once got a number of these switches of a friend of mine.

      BTW the clock radio has a led strip connected emulating a Wakeup light, shows the out door temperature on request, since it is MYS connected the alarm can be triggered via my HA controller and the most important feature it switches on my coffee machine upon wake up time.

      I will post a detailed description in the comming days,

      posted in General Discussion
      BartE
      BartE
    • RE: Multi RF433 Switches Node

      @OliverDog Sorry my (beginners) fault the array's are counting from 0 to 8 and the sensor numbers from 1 till 9

      This should work:

      #define MY_DEBUG 
      #define MY_RADIO_NRF24
      #include <SPI.h>
      #include <MySensors.h>
      #include <livolo.h>
      
      #define CHILD_ID 1
      
      Livolo livolo(8);
      
      bool initValSent[]   = {false, false, false, false, false, false, false, false, false};
      int livoloSensCode[] = {120, 70, 1, 2, 3, 4, 5, 6, 7}; // Set correct livolo codes here
      
      MyMessage msg(CHILD_ID, V_STATUS);
      
      void setup() {
        
      }
      
      void presentation()  {   
        sendSketchInfo("Livolo", "1.0");
        for (int sensor=1; sensor<=9; sensor++) { 
          // (presents each sensor, S_BINARY type)
          present(sensor, S_BINARY);
        }
      }
      
      void loop() {
        for (int sensor=1; sensor<=9; sensor++) { 
          if (!initValSent[sensor-1]) {
            msg.setSensor(sensor);
            send(msg.set(false)); 
            Serial.print("Requesting initial value for sensor: ");
            Serial.println(sensor);
            request(sensor, V_STATUS);
            wait(2000, C_SET, V_STATUS);
          }
        }
      }
      
      void receive(const MyMessage &message) {
        switch (message.type) {
          case V_LIGHT:
             if (!initValSent[message.sensor-1]) {
                Serial.print("Receiving initial value from controller for sensor: ");
                initValSent[message.sensor-1] = true;
             } else {
                Serial.print("Receiving new value for sensor: ");
                livolo.sendButton(6400, livoloSensCode[message.sensor-1]); // coded for each sensor 
             }  
             Serial.println(message.sensor);  
             break;
        }
      }
      
      
      posted in Development
      BartE
      BartE
    • RE: RelayWithButtonActuator (6 channel)

      @vampircik i see that with some help from korttoma you manage to find the correct pins setting. @korttoma thx for your help.
      korttoma is right about the pin 11, i should have added this link with more background info

      The sketch is designed for push buttons and not for toggle switches and will respond when releasing a button press.
      In your movie i see that switching on and off via MySensors (mouse clicks) works but the button presses not (always) only switching off.

      I found an error in my sketch on line 131

      // Store new switch value
      switches[id].currentStatus = (switchValue ? 0 : 1);
      
      

      the correct line should be

      // Toggle relay status
      switches[id].currentStatus = (switches[id].currentStatus ? 0 : 1);
      
      

      note: I've updated the sketch in the original post as well

      posted in My Project
      BartE
      BartE
    • RE: IR Record and Playback module

      This sketch has been updated to MySensors 2.0 and added example library https://www.mysensors.org/build/ir

      posted in My Project
      BartE
      BartE
    • RE: Humidity+Relay with button node

      @thecko said:

      The problem is in the "state" variable, you use the state variable to toggle but never save changed value

      so change this code snippet

         debouncer.update();
         int value = debouncer.read();
         if (value != oldValue && value==0) {
             gw.send(msg.set(state?false:true), true); // Send new state and request ack back
         }
         oldValue = value;
      

      to

         debouncer.update();
         int value = debouncer.read();
         if (value != oldValue && value==0) {
             gw.send(msg.set(gw.loadState(1)?false:true), true); // Send new state and request ack back
         }
         oldValue = value;
      

      and remove the state variable at all.

      Even better also remove the "oldValue" and "value" variables (the bounce2 library keeps the old value for you and debouncer.update(); returns true when the value was toggled )

         if (debouncer.update() && debouncer.read() == 0) {
             gw.send(msg.set(gw.loadState(1)?false:true), true); // Send new state and request ack back
         }
      
      posted in Development
      BartE
      BartE
    • RE: How can I control a servo with Mysensors? Automatic cat feeder

      @chuckconnors funny project!

      Arduino has a servo library take a look here

      Your sketch can be the relay sketch like mfalkvidd says (use pin 6 i.s.o. 9 because 9 is used by the radio)

      Servo myservo;  // create servo object to control a servo
      
      void setup()  {
         ...
         myservo.attach(6);  // attaches the servo on pin 6 to the servo object
         ...
      }
      

      And in the message handler

      if (message.getBool()){
          // Open door 90 degrees
          myservo.write(90);
      } else {
          // Close door 0 degrees
          myservo.write(0);
      }
      
      posted in General Discussion
      BartE
      BartE
    • RE: IR Record and Playback module

      @pete1450 i've added your feature request in version 1.1 of my plug in sketch You can add up to 240 RC HEX commands, from line 111, if you use an Arduino with enough memory. 40 will do with an Arduino UNO

      /**
       * The MySensors Arduino library handles the wireless radio link and protocol
       * between your home built sensors/actuators and HA controller of choice.
       * The sensors forms a self healing radio network with optional repeaters. Each
       * repeater and gateway builds a routing tables in EEPROM which keeps track of the
       * network topology allowing messages to be routed to nodes.
       *
       * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
       * Copyright (C) 2013-2015 Sensnology AB
       * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
       *
       * Documentation: http://www.mysensors.org
       * Support Forum: http://forum.mysensors.org
       *
       * This program is free software; you can redistribute it and/or
       * modify it under the terms of the GNU General Public License
       * version 2 as published by the Free Software Foundation.
       *
       *******************************
       *
       * REVISION HISTORY
       * Version 1.0 - Changed for MySensors useage by Bart Eversdijk
       * Version 1.1 - Added option to record manual presets up to 240
       * 
       * DESCRIPTION
       *
       * IRrecord: record and play back IR signals as a minimal 
       * An IR detector/demodulator must be connected to the input RECV_PIN.
       * An IR LED must be connected to the output PWM pin 3.
       * A button must be connected to the input BUTTON_PIN; this is the
       * send button.
       * A visible LED can be connected to STATUS_PIN to provide status.
       *
       * The logic is:
       * If the button is pressed, send the IR code.
       * If an IR code is received, record it.
       *
       * Version 0.11 September, 2009
       * Copyright 2009 Ken Shirriff
       * http://arcfn.com
       */
      
      #include <MySensor.h>
      #include <SPI.h>
      #include <IRremote.h>  // https://github.com/z3t0/Arduino-IRremote/releases
      
      int RECV_PIN     = 8;
      #define NODEID   5
      //#define NODEID   NULL
      #define CHILD_1  2  // childId
      
      #define MY_RAWBUF  50
      const char * TYPE2STRING[] = {
      		"UNKONWN",
      		"RC5",
      		"RC6",
      		"NEC",
      		"Sony",
      		"Panasonic",
      		"JVC",
      		"SAMSUNG",
      		"Whynter",
      		"AIWA RC T501",
      		"LG",
      		"Sanyo",
      		"Mitsubishi",
      		"Dish",
      		"Sharp",
      		"Denon"
      };
      #define Type2String(x)   TYPE2STRING[x < 0 ? 0 : x]
      #define AddrTxt          F(" addres: 0x")
      #define ValueTxt         F(" value: 0x")
      #define NATxt            F(" - not implemented/found")
      
      // Raw or unknown codes requires an Arduino with a larger memory like a MEGA and some changes to store in EEPROM (now max 255 bytes)
      // #define IR_SUPPORT_UNKNOWN_CODES
      typedef union
      {
        struct
        {
          decode_type_t type;            // The type of code
          unsigned long value;           // The data bits if type is not raw
          int           len;             // The length of the code in bits
          unsigned int  address;         // Used by Panasonic & Sharp [16-bits]
        } code;
      #ifdef IR_SUPPORT_UNKNOWN_CODES      
        struct
        {
          decode_type_t type;             // The type of code
          unsigned int  codes[MY_RAWBUF];
          byte          count;           // The number of interval samples
        } raw;
      #endif
      } IRCode;
      
      #define           MAX_STORED_IR_CODES     10
      IRCode            StoredIRCodes[MAX_STORED_IR_CODES];
      
      IRrecv            irrecv(RECV_PIN);
      IRsend            irsend;
      decode_results    ircode;
      
      #define           NO_PROG_MODE 0xFF
      byte              progModeId       = NO_PROG_MODE;
      
      // Manual Preset IR values
      // VERA call: luup.call_action("urn:schemas-arduino-cc:serviceId:ArduinoIr1", "SendIrCode", {Index=15}, <device number>)
      // One can add up to 240 preset codes (if your memory lasts) to see to correct data connect the Arduino with this plug in and
      // look at the serial monitor while pressing the desired RC button
      IRCode PresetIRCodes[] = {
          { { RC5, 0x01,       12, 0 } },  // 11 - RC5 key "1" 
          { { RC5, 0x02,       12, 0 } },  // 12 - RC5 key "2"
          { { RC5, 0x03,       12, 0 } },  // 13 - RC5 key "3"
          { { NEC, 0xFF30CF,   32, 0 } },  // 14 - NEC key "1"
          { { NEC, 0xFF18E7,   32, 0 } },  // 15 - NEC key "2"
          { { NEC, 0xFF7A85,   32, 0 } },  // 16 - NEC key "3"
          { { NEC, 0xFF10EF,   32, 0 } },  // 17 - NEC key "4"
          { { NEC, 0xFF38C7,   32, 0 } },  // 18 - NEC key "5"
          { { RC6, 0x800F2401, 36, 0 } },  // 19 - RC6 key "1" MicroSoft Mulitmedia RC
          { { RC6, 0x800F2402, 36, 0 } }   // 20 - RC6 key "2" MicroSoft Mulitmedia RC
      };
      #define MAX_PRESET_IR_CODES  (sizeof(PresetIRCodes)/sizeof(IRCode))
      #define MAX_IR_CODES (MAX_STORED_IR_CODES + MAX_PRESET_IR_CODES)
      
      MySensor gw;
      MyMessage msgIrReceive(CHILD_1, V_IR_RECEIVE);
      MyMessage msgIrRecord(CHILD_1, V_IR_RECORD); 
      
      void setup()  
      {  
        gw.begin(incomingMessage, NODEID);
      
        // Send the sketch version information to the gateway and Controller
        gw.sendSketchInfo("IR Rec/Playback", "1.1");
      
        // Register a sensors to gw. Use binary light for test purposes.
        gw.present(CHILD_1, S_IR);
      
        // Tell MYS Controller that we're NOT recording
        gw.send(msgIrRecord.set(0));
        
        Serial.println(F("Recall EEPROM settings"));
        recallEeprom(sizeof(StoredIRCodes), (byte *)&StoredIRCodes);
      
        // Start the ir receiver
        irrecv.enableIRIn(); 
        
        Serial.println(F("Init done..."));
      }
      
      void loop() 
      {
        gw.process();
        
        if (irrecv.decode(&ircode)) {
            dump(&ircode);
            if (progModeId != NO_PROG_MODE) {
               // If we are in PROG mode (Recording) store the new IR code and end PROG mode
               if (storeRCCode(progModeId)) {
                  Serial.print(F("Stored "));
                
                  // If sucessfull RC decode and storage --> also update the EEPROM
                  storeEeprom(sizeof(StoredIRCodes), (byte *)&StoredIRCodes);
                  progModeId = NO_PROG_MODE;
                 
                  // Tell MYS Controller that we're done recording
                  gw.send(msgIrRecord.set(0));
               }
            } else {
               // If we are in Playback mode just tell the MYS Controll we did receive an IR code
               if (ircode.decode_type != UNKNOWN) {
                   if (ircode.value != REPEAT) {
                     // Look if we found a stored preset 0 => not found
                     byte num = lookUpPresetCode(&ircode);
                     if (num) {
                         // Send IR decode result to the MYS Controller
                         Serial.print(F("Found code for preset #"));
                         Serial.println(num);
                         gw.send(msgIrReceive.set(num));
                     }
                   }
               }
          }
          // Wait a while before receive next IR-code
          delay(500);
          
          // Start receiving again
          irrecv.resume();
        }
      }
      
      void incomingMessage(const MyMessage &message) {
          //Serial.print(F("New message: "));
          //Serial.println(message.type);
         
         if (message.type == V_IR_RECORD) { // IR_RECORD V_VAR1
            // Get IR record requets for index : paramvalue
            progModeId = message.getByte() % MAX_STORED_IR_CODES;
            
            // Tell MYS Controller that we're now in recording mode
            gw.send(msgIrRecord.set(1));
            
            Serial.print(F("Record new IR for: "));
            Serial.println(progModeId);
         }
        
         if (message.type == V_IR_SEND) {
            // Send an IR code from offset: paramvalue - no check for legal value
            Serial.print(F("Send IR preset: "));
            byte code = message.getByte() % MAX_IR_CODES;
            if (code == 0) {
              code = MAX_IR_CODES;
            }
            Serial.print(code);
            sendRCCode(code);
         }
      
         // Start receiving ir again...
         irrecv.enableIRIn(); 
      }
      
      
      byte lookUpPresetCode (decode_results *ircode)
      {
          // Get rit of the RC5/6 toggle bit when looking up
          if (ircode->decode_type == RC5)  {
              ircode->value = ircode->value & 0x7FF;
          }
          if (ircode->decode_type == RC6)  {
              ircode->value = ircode->value & 0xFFFF7FFF;
          }
          for (byte index = 0; index < MAX_STORED_IR_CODES; index++) {
            if ( StoredIRCodes[index].code.type  == ircode->decode_type &&
                 StoredIRCodes[index].code.value == ircode->value       &&
                 StoredIRCodes[index].code.len   == ircode->bits)      {
                // The preset number starts with 1 so the last is stored as 0 -> fix this when looking up the correct index
                return (index == 0) ? MAX_STORED_IR_CODES : index;
            }  
          }
          
          for (byte index = 0; index < MAX_PRESET_IR_CODES; index++) {
            if ( PresetIRCodes[index].code.type  == ircode->decode_type &&
                 PresetIRCodes[index].code.value == ircode->value       &&
                 PresetIRCodes[index].code.len   == ircode->bits)      {
                // The preset number starts with 1 so the last is stored as 0 -> fix this when looking up the correct index
                return ((index == 0) ? MAX_PRESET_IR_CODES : index) + MAX_STORED_IR_CODES;
            }  
          }
          // not found so return 0
          return 0;
      }
          
      // Stores the code for later playback
      bool storeRCCode(byte index) {
      
        if (ircode.decode_type == UNKNOWN) {
      #ifdef IR_SUPPORT_UNKNOWN_CODES  
            Serial.println(F("Received unknown code, saving as raw"));
            // To store raw codes:
            // Drop first value (gap)
            // As of v1.3 of IRLib global values are already in microseconds rather than ticks
            // They have also been adjusted for overreporting/underreporting of marks and spaces
            byte rawCount = min(ircode.rawlen - 1, MY_RAWBUF);
            for (int i = 1; i <= rawCount; i++) {
              StoredIRCodes[index].raw.codes[i - 1] = ircode.rawbuf[i]; // Drop the first value
            };
            return true;
      #else 
            return false;
          }
      #endif
      
         if (ircode.value == REPEAT) {
             // Don't record a NEC repeat value as that's useless.
             Serial.println(F("repeat; ignoring."));
             return false;
         }
         // Get rit of the toggle bit when storing RC5/6 
         if (ircode.decode_type == RC5)  {
              ircode.value = ircode.value & 0x07FF;
         }
         if (ircode.decode_type == RC6)  {
              ircode.value = ircode.value & 0xFFFF7FFF;
         }
      
         StoredIRCodes[index].code.type      = ircode.decode_type;
         StoredIRCodes[index].code.value     = ircode.value;
         StoredIRCodes[index].code.address   = ircode.address;      // Used by Panasonic & Sharp [16-bits]
         StoredIRCodes[index].code.len       = ircode.bits;
         Serial.print(F(" value: 0x"));
         Serial.println(ircode.value, HEX);
         return true;
      }
      
      void sendRCCode(byte index) {
         IRCode *pIr = ((index <= MAX_STORED_IR_CODES) ? &StoredIRCodes[index % MAX_STORED_IR_CODES] : &PresetIRCodes[index - MAX_STORED_IR_CODES - 1]);
         
      #ifdef IR_SUPPORT_UNKNOWN_CODES  
         if(pIr->code.type == UNKNOWN) {
            // Assume 38 KHz
            irsend.sendRaw(pIr->raw.codes, pIr->raw.count, 38);
            Serial.println(F("Sent raw"));
            return;
         }
      #endif
      
         Serial.print(F(" - sent "));
         Serial.print(Type2String(pIr->code.type));
         if (pIr->code.type == RC5) {
             // For RC5 and RC6 there is a toggle bit for each succesor IR code sent alway toggle this bit, needs to repeat the command 3 times with 100 mS pause
             pIr->code.value ^= 0x0800;
             for (byte i=0; i < 3; i++) {
               if (i > 0) { delay(100); } 
               irsend.sendRC5(pIr->code.value, pIr->code.len);
             }
          } 
          else if (pIr->code.type == RC6) {
             // For RC5 and RC6 there is a toggle bit for each succesor IR code sent alway toggle this bit, needs to repeat the command 3 times with 100 mS pause
             if (pIr->code.len == 20) {
                    pIr->code.value ^= 0x10000;
             }
             for (byte i=0; i < 3; i++) {
               if (i > 0) { delay(100); } 
               irsend.sendRC6(pIr->code.value, pIr->code.len);
             }
         }
         else if (pIr->code.type == NEC) {
             irsend.sendNEC(pIr->code.value, pIr->code.len);
          } 
          else if (pIr->code.type == SONY) {
             irsend.sendSony(pIr->code.value, pIr->code.len);
          } 
          else if (pIr->code.type == PANASONIC) {
             irsend.sendPanasonic(pIr->code.address, pIr->code.value);
             Serial.print(AddrTxt);
             Serial.println(pIr->code.address, HEX);
          }
          else if (pIr->code.type == JVC) {
             irsend.sendJVC(pIr->code.value, pIr->code.len, false);
          }
          else if (pIr->code.type == SAMSUNG) {
             irsend.sendSAMSUNG(pIr->code.value, pIr->code.len);
          }
          else if (pIr->code.type == WHYNTER) {
             irsend.sendWhynter(pIr->code.value, pIr->code.len);
          }
          else if (pIr->code.type == AIWA_RC_T501) {
             irsend.sendAiwaRCT501(pIr->code.value);
          }
          else if (pIr->code.type == LG || pIr->code.type == SANYO || pIr->code.type == MITSUBISHI) {
             Serial.println(NATxt);
             return;
          }
          else if (pIr->code.type == DISH) {
            // need to repeat the command 4 times with 100 mS pause
            for (byte i=0; i < 4; i++) {
               if (i > 0) { delay(100); } 
                 irsend.sendDISH(pIr->code.value, pIr->code.len);
            }
          }
          else if (pIr->code.type == SHARP) {
             irsend.sendSharp(pIr->code.address, pIr->code.value);
             Serial.print(AddrTxt);
             Serial.println(pIr->code.address, HEX);
          }
          else if (pIr->code.type == DENON) {
             irsend.sendDenon(pIr->code.value, pIr->code.len);
          }
          else {
            // No valid IR type, found it does not make sense to broadcast
            Serial.println(NATxt);
            return; 
          }
          Serial.print(" ");
          Serial.println(pIr->code.value, HEX);
      }    
      
      // Dumps out the decode_results structure.
      void dump(decode_results *results) {
          int count = results->rawlen;
          
          Serial.print(F("Received : "));
          Serial.print(results->decode_type, DEC);
          Serial.print(F(" "));
          Serial.print(Type2String(results->decode_type));
        
          if (results->decode_type == PANASONIC) {	
            Serial.print(AddrTxt);
            Serial.print(results->address,HEX);
            Serial.print(ValueTxt);
          }
          Serial.print(F(" "));
          Serial.print(results->value, HEX);
          Serial.print(F(" ("));
          Serial.print(results->bits, DEC);
          Serial.println(F(" bits)"));
        
          if (results->decode_type == UNKNOWN) {
            Serial.print(F("Raw ("));
            Serial.print(count, DEC);
            Serial.print(F("): "));
        
            for (int i = 0; i < count; i++) {
              if ((i % 2) == 1) {
                Serial.print(results->rawbuf[i]*USECPERTICK, DEC);
              } else {
                Serial.print(-(int)results->rawbuf[i]*USECPERTICK, DEC);
              }
              Serial.print(" ");
            }
            Serial.println("");
          }
      }
      
      // Store IR record struct in EEPROM   
      void storeEeprom(byte len, byte *buf)
      {
          gw.saveState(0, len);
          for (byte i = 1; i < min(len, 100); i++, buf++) {
             gw.saveState(i, *buf);
          }
      }
      
      void recallEeprom(byte len, byte *buf)
      {
          if (gw.loadState(0) != len) {
             Serial.print(F("Corrupt EEPROM preset values and Clear EEPROM"));
             for (byte i = 1; i < min(len, 100); i++, buf++) {
                 *buf = 0;
                 storeEeprom(len, buf);
             }
             return;
          }
          for (byte i = 1; i < min(len, 100); i++, buf++) {
             *buf = gw.loadState(i);
          }
      }
      

      I will update the Vera code as well in git
      With Vera this luup code controlls the extra presets:
      luup.call_action("urn:schemas-arduino-cc:serviceId:ArduinoIr1", "SendIrCode", {Index=15}, <device number>)

      Vera UI5 Screen shot:
      upload-0bb76cf0-b984-4b30-b9b3-cfb03ffe9648

      posted in My Project
      BartE
      BartE
    • RE: NeoPixel( S_RGB_LIGHT) with Vera 3 (UI 5) - SOLVED

      @ar91 I had simulair problems with the RGB-plugin from vosmont. See this forum post .

      Vera has an issue with child-parent controlled plugins. The init procedure is called twice in specific cases, and in this case your MSY plugin in not able to open the serial port twice (which is logical). The solution is delete the MYS generated plug-in tile, in your screen capture the left RGB tile. (which is a child plug-in) and use a manual created plug-in tile (with Vera create device) which has no child-parent relation.

      Let this manual created plugin control your RGB device by configuring the correct MYS- ID and device node ID. By following this procedure:

      • Change the setting of te RGB controller (wrench-icon, Settings-tab)
      • Select: MySensors RGBW
      • Arduino plugin Id: <enter MyS GW device ID >
      • RGB Node altid: <enter node ID in your example 62>
      • Press save button
      posted in Troubleshooting
      BartE
      BartE
    • RE: UI5 Mysensors library 2.0 gateway issues

      @hek andf @martinhjelmare i did some debugging this evening and came to the following findings

      My previous comment on start-up behavior was based on a stand alone GW (so disconnected from the Vera Controller)
      And i found out that the Library version is NOT pushed by the gateway but requested by the controller on plugin startup.

      And this part (on GW side is working) --> Sending "0;0;0;3;0;2;Get Version" to the GW is being answered with "0;255;3;0;2;2.0.0"

      So it must be the Vera plugin and then i found this line in my Vera box

      02      07/30/16 23:23:43.694   luup_log:64: Arduino: Incoming internal command '0;255;3;0;2;2.0.0' discarded for child: nil <0x6c14>
      

      So the MySensors v2.0.0 GW responses with alt-id 0;255 i.s.o 0;0
      By updating this line https://github.com/mysensors/Vera/blob/development/L_Arduino.lua#L370 by... auhm what is already in the current git version it works.

      So the final conclusion: just update the Vera plugin with the development branch and it works...

      posted in Vera
      BartE
      BartE
    • Controlling a 1st gen. LivingColors lamp

      Having a first generation LivingColors lamp sitting around for a couple a years, mostly doing nothing because the RC batteries are worn out with 6 weeks. I was browsing the internet when a ran into a old project post on knutsel.org describing a LivingColors RC based on Arduino UNO shield, when i decided to give the LC a second life 🙂

      I ordered a build and tested CC2500 shield and mounted a NRF24L01+ Radio module on the board itself. It has plenty of mount space left.

      Since the 2500 uses the SPI interface as well i had to use alternative pins for CS and CE. This is how i connected the radio
      0_1454973348897_LivingColorRemote.png

      The build device
      0_1454973369008_LivingColorCC2500MyS_small.jpg

      For controlling the lamp i'd used vosmont RGB contoller plugin as described in this post

      This is the Arduino sketch (please make sure you install the CC2500 library from knutsel.org

      /**
       * REVISION HISTORY
       * Version 1.0 - Februari 2016 - Bart Eversdijk
       *
       * DESCRIPTION
       * This sketch provides a LivingColor 1st generation  RGB controller 
       * 
       * Based on the CC2500 sheild from http://www.knutsel.org/tag/arduino-shield/
       *
       * Optimized for usage with vosmont RGB colorwheel MicsaVerde Vera plug in 
       * https://github.com/vosmont/Vera-Plugin-RGBController and http://forum.micasaverde.com/index.php?topic=32613.0
       *
       */
      #include <CC2500.h>
      #include <ColourConversion.h>
      #include <LivingColors.h>
      #include <MyTransportNRF24.h>
      #include <MyHwATMega328.h>
      #include <SPI.h>
      #include <MySensor.h>
      
      
      #define lcMOSI   11    // SPI master data out pin
      #define lcMISO   12    // SPI master data in pin
      #define lcSCK    13    // SPI clock pin
      #define lcCS     10    // SPI slave select pin
      
      #define MY_RF24_CE_PIN  6
      #define MY_RF24_CS_PIN  7
      
      // NRFRF24L01 radio driver (set low transmit power by default) 
      MyTransportNRF24 radio(MY_RF24_CE_PIN, MY_RF24_CS_PIN, RF24_PA_LEVEL_GW);  
      // Select AtMega328 hardware profile
      MyHwATMega328 hw;
      // Construct MySensors library
      MySensor gw(radio, hw);
      
      LivingColors livcol(lcCS, lcSCK, lcMOSI, lcMISO);
      
      #define lampId  0
      unsigned char lamp1[9] = { 0x07, 0x1C, 0x19, 0x10, 0x39, 0xF9, 0x3C, 0xB9, 0x11 }; // Lamp Woonkamer
      
      enum ANIMATIOMODES {RAINBOW=0,RANDONMIZE,FADERGB,FADEMULTICOLR,FLASHCOLOR,LAST_PROGRAM};
      char *ANIMATIOMODES_TXT[] = { "RAINBOW","RANDONMIZE","FADERGB","FADEMULTICOLR","FLASHCOLOR" };
      byte FADE_RGB_COLOR_MODES[]   = {0b0010,0b0011,0b0100,0b0101,0b1000,0b1001, 0xFF};
      byte FADE_MULTI_COLOR_MODES[] = {0b0010,0b0011,0b0110,0b0111,0b0100,0b0101,0b1100,0b1101,0b1000,0b1001,0b1010,0b1011,0xFF};
                                // RRGBU
      byte COLOR_WHEEL_MODES[] = {0b0101, 0b0010, 0b1001, 0b0100, 0b0011, 0b1000, 0xFF};
      
      byte ledOffValues[] = {0, 0, 0};
      byte rgb_values[]   = {0, 0, 0};
      
      byte speedtable[] = { 0, 400, 100, 20 };
      //int speedtable[] = { 0, 50, 25, 2 };
      #define NUM_OF_SPEEDS sizeof(speedtable)
      #define CHAR2BYTE(x)   (byte)(x > '9' ? (x > 'F' ? (x + 10 - 'a') : (x + 10 - 'A')) : x - '0')
      
      struct
      {
         byte values[3];
         byte speedsetting;
         byte mode;
         bool status;
         byte dimlevel;
      } rgb = { {0,0,0}, 0, RAINBOW, false, 0};
      
      bool              flashOn      = true;
      unsigned long     syscounter   = 0;
      unsigned long     lastUpdate   = 0;
      bool              newSetting   = false;
      
      
      void setup() {
          // Initialize library and add callback for incoming messages
          gw.begin(incomingMessage, AUTO, true);
          // Send the sketch version information to the gateway and Controller
          gw.sendSketchInfo("LivingColor", "1.0");
          
          // Do not present for Vera see forum post: http://forum.mysensors.org/topic/2160/my-mysensors-rgbw-plug-in-has-an-init-problem
          //gw.present(0, S_RGB_LIGHT);
          
          livcol.init();
          livcol.clearLamps();
          livcol.addLamp(lamp1);
      
          recallEeprom();
          if (rgb.status) {
             livcol.turnLampOnRGB(lampId, rgb_values[0], rgb_values[1], rgb_values[2]); 
          }
          delay(10); 
          
          Serial.println("Init done");
      }
      
      void loop()
      {
          // Alway process incoming messages whenever possible
          gw.process();
      
          if (rgb.status && speedtable[rgb.speedsetting] > 0) {
              if ((syscounter % speedtable[rgb.speedsetting]) == 0) {
                 switch (rgb.mode)
                 {
                     case RAINBOW:
                       animateRainbowStep();
                       break;
      
                     case FADERGB:
                       animateFadeColorStep(FADE_RGB_COLOR_MODES);
                       break;
      
                     case FADEMULTICOLR:
      //                 animateFadeColorStep(FADE_MULTI_COLOR_MODES);
                       animateColorWheelStep(COLOR_WHEEL_MODES);
                       break;
                   
                    case FLASHCOLOR:
                       setLedValues(flashOn ? ledOffValues : rgb.values, false);
                       flashOn = !flashOn;
                       break;
                                   
                     case RANDONMIZE:
                       rgb_values[0] = (byte)random(0, rgb.dimlevel);
                       rgb_values[1] = (byte)random(0, rgb.dimlevel);
                       rgb_values[2] = (byte)random(0, rgb.dimlevel);
                       setLedValues(rgb_values, false);
                       break;
                 }
              }
              delay(rgb.mode == RANDONMIZE || rgb.mode == FLASHCOLOR ? 50 : 1);
          }
          
          if (newSetting && (lastUpdate + 20000 < syscounter)) {   
              // Wait for a couple of seconds be fore actual storing the current setting into EEPROM
              // This will save the EEPROM's life time, when playing around with colors
              Serial.println(" Store EERPOM");
              storeEeprom();
              newSetting = false;
          } 
          
          gw.wait(3);
          syscounter++;
      }
      
      void animateRainbowStep()
      {    
          static float counter = 0;
          float        pi      = 3.14159; 
          counter++;
          rgb_values[0] = map(sin(counter/100         )*1000,-1000,1000,0,0xFF);
          rgb_values[1] = map(sin(counter/100 + pi*2/3)*1000,-1000,1000,0,0xFF);
          rgb_values[2] = map(sin(counter/100 + pi*4/3)*1000,-1000,1000,0,0xFF);
          setLedValues(rgb_values, false);
      }
      
      void animateFadeColorStep(byte *modes)
      {    
          static int modecnt = 0;
          if (updateRGBValues(modes[modecnt] >> 1, (modes[modecnt] & 0x1) == 0x1)) { 
              modecnt = (modes[modecnt+1] == 0xFF ? 0 : modecnt + 1);
          }
      }
      
      void animateColorWheelStep(byte *modes)
      {    
          static int modecnt = 0;
          for (byte i = 0; i < 3; i++) {
              if ((modes[modecnt] >> (i + 4) & 0x1) == 0x1) {
                 rgb_values[i] = 0xFF;
              }
          }
          if (updateRGBValues(modes[modecnt] >> 1, (modes[modecnt] & 0x1) == 0x1)) { 
              modecnt = (modes[modecnt+1] == 0xFF ? 0 : modecnt + 1);
          }
      }
      
      
      bool updateRGBValues(byte mode, bool down)
      {
          bool endReached = false;
          for (byte i = 0; i < 3; i++) {
              if (((mode >> i) & 0x1) == 0x1) {
                 rgb_values[i] += (down ? -1 : 1);
                 endReached    |= (down && (rgb_values[i] == 0x00)) || (!down && (rgb_values[i] == 0xFF));
              }
          }
          setLedValues(rgb_values, false);
          return endReached;
      }
      
      
      void incomingMessage(const MyMessage &message) {
          if (message.isAck()) {
              Serial.println("GW acknowledge");
          }
          
          if (message.type == V_RGB || message.type == V_RGBW) {
      	// starting to process the hex code
              const char * hexstring  = message.getString();
              rgb.values[0]    = (CHAR2BYTE(hexstring[0]) << 4) + CHAR2BYTE(hexstring[1]);
              rgb.values[1]    = (CHAR2BYTE(hexstring[2]) << 4) + CHAR2BYTE(hexstring[3]);
              rgb.values[2]    = (CHAR2BYTE(hexstring[4]) << 4) + CHAR2BYTE(hexstring[5]);
              rgb.dimlevel     = (CHAR2BYTE(hexstring[6]) << 4) + CHAR2BYTE(hexstring[7]);
              
              rgb.speedsetting = 0;  // new color is set stop animation (if is was running)
              if (!rgb.status) {
                  // Switch on if the status was off
                  rgb.status  = 1;  
                  livcol.turnLampOnRGB(lampId, rgb.values[0], rgb.values[1], rgb.values[2]); 
              }
              setLedValues(rgb.values, true);
              lastUpdate       = syscounter;
              newSetting       = true;
          }
          
          if (message.type == V_STATUS) {
             if (message.getBool()) {
                 Serial.println("ON: Switch to last known color values/or start the last known animation");
                 livcol.turnLampOnRGB(lampId, rgb.values[0], rgb.values[1], rgb.values[2]); 
             } else {
                 Serial.println("OFF: Switch colors off");
                 livcol.turnLampOff(lampId);
             }
             rgb.status = message.getBool();
             lastUpdate = syscounter;
             newSetting = true;
          }
          
          if (message.type == V_VAR1) {
             Serial.println("Set speed and program value"); 
             const char * newsetting = message.getString();
             rgb.speedsetting = CHAR2BYTE(newsetting[0]);
             byte newmode     = CHAR2BYTE(newsetting[1]);
      
             if (newmode != rgb.mode) {
                 for (byte i = 0; i < 3; i++) {
                     rgb_values[i] = 0;
                 }
                 rgb.mode = newmode;
             }
             if (rgb.speedsetting > 0) {
                 rgb.status = true;
             }
             lastUpdate = syscounter;
             newSetting = true;
            
             Serial.print("Speed:");
             Serial.print(rgb.speedsetting);
             Serial.print(" mode: ");
             Serial.print(rgb.mode);
             Serial.print(" ");
             Serial.println(ANIMATIOMODES_TXT[rgb.mode]);
          }
      }
      
      
      void setLedValues(byte *setrgb, bool show)
      {
          static byte oldrgb[] = {0, 0, 0};
          
          byte newrgb[] = {0, 0, 0};
          newrgb[0] = map(setrgb[0],0,0xFF,0,show?0xFF:rgb.dimlevel);
          newrgb[1] = map(setrgb[1],0,0xFF,0,show?0xFF:rgb.dimlevel);
          newrgb[2] = map(setrgb[2],0,0xFF,0,show?0xFF:rgb.dimlevel);
          
          bool update = (newrgb[0] != oldrgb[0]) || (newrgb[1] != oldrgb[1]) || (newrgb[2] != oldrgb[2]);
          oldrgb[0] = newrgb[0];
          oldrgb[1] = newrgb[1];
          oldrgb[2] = newrgb[2];
          
          if (update) {
             livcol.setLampColourRGB(lampId, newrgb[0], newrgb[1], newrgb[2]); 
          }
          if (show) {
             Serial.print("Red: " );
             Serial.print(newrgb[0], HEX);
             Serial.print("  Green: " );
             Serial.print(newrgb[1], HEX);
             Serial.print("  Blue: " );
             Serial.print(newrgb[2], HEX);
             Serial.print("  dim level: " );
             Serial.println(rgb.dimlevel, HEX);
          }
      }
      
      void storeEeprom()
      {
          byte address = 0;
          byte *p = (byte *)&(rgb);
          for (byte i = 0; i < sizeof(rgb); i++) {
             gw.saveState(address++, p[i]);
          }
      }
      
      void recallEeprom()
      {
          byte address = 0;
          byte *p = (byte *)&(rgb);
          for (byte i = 0; i < sizeof(rgb); i++) {
             p[i] = gw.loadState(address++);
          }
      }
      

      And this is some action footage of the end result:
      LivingColors – 02:21
      — BeEeBart

      posted in My Project
      BartE
      BartE
    • RE: Car Aux Battery Monitor

      @Boots33 thanks for sharing, this project inspired me to have a monitor for my caravan battery 🙂

      I have mine up and running now and did run in a small error present in your source code, on this line

       present(ID_S_MULTIMETERV,V_VOLTAGE);               // Register Sensor to gateway 
      

      The present function should contain sensor type (S_xxxx values) and V_VOLTAGE is a payload message type.
      So i think the presentation function should look like this.

      void presentation()
      {
        sendSketchInfo("Battery Sensor", "1.1");    // Send the sketch version information to the gateway and Controller
        present(ID_S_MULTIMETERV, S_MULTIMETER);       // Register Sensor to gateway
      }
      

      Up and 'running':
      0_1507639148752_accumonitor.png

      posted in My Project
      BartE
      BartE
    • RE: Using nrf24l01+ with other devices together on one SPI-Bus.

      @Michał-Owsianka Yes

      @BartE said:

      pin 7 (iso 9) for CE
      pin 8 (iso 10) for CSN/CS

      Pin 7 CE == RST
      Pin 8 CSN/CS == SDA

      The init part of the code can be found in my earlier post
      The rest of the library is taken from the mfrc522 example code. https://github.com/miguelbalboa/rfid

      To share my Sketch i do need to cleanup and test again the Sketch because it does (much) more. Like reading temperature and air pressure.

      posted in Development
      BartE
      BartE
    • RE: VeraPlus Serial Gateway Not Recognized

      @smint I do not have any VeraPlus expecience but i do use a Vera2 and Vera3.

      I my case sometime the USB gateway is nog recongised by Vera.
      My start up procedure:

      • switch on Vera (without USB GW)
      • wait a while to let it boot
      • connect the MySensors GW (make sure the USB light comes on, not sure if a VeraPlus has a USB led)
      • press reload button in UI (if the USB port is not shown in port configuration)
      • again wait for Vera to be ready
      • go to serial port config to see is port is available now. Make sure you set the serial speed (baud) setting correct and press save
      posted in Vera
      BartE
      BartE
    • RE: Array Relay Button Actuator

      @niccodemi You can forget using the oldValue, because the debounce takes track of it's last status. When update() is called and a debounced pin-change is detect this function will return true otherwise it will send false.
      Having a short delay each loop will stabilize the debouncers so your loop() can look like this:

      void loop()
      {
          for (byte i = 0; i < noRelays; i++) {
              if (debouncer[i].update()) {
                  Relays[i].relayState = !Relays[i].relayState;
                  digitalWrite(Relays[i].relayPin, Relays[i].relayState?RELAY_ON:RELAY_OFF);
                  send(msg[i].set(Relays[i].relayState? true : false));
                  // save sensor state in EEPROM (location == sensor number)
                  saveState( i, Relays[i].relayState );
              }                 
          }
          wait(10);
      }
      
      posted in General Discussion
      BartE
      BartE
    • RE: My own board (50mm x 30mm)

      @GertSanders just to let you known i did plat around a little bit with your PCB design and i found a way to use is with-out the crystal by using the ATmega's internal 8 MHz clock

      See the results here: http://forum.mysensors.org/topic/2484/running-atmega328p-on-internal-8mhz-clock

      The free PCB space (where the clock Cap's and crystal was designed) i now use for the big transmitter capacitor to lay down.

      posted in My Project
      BartE
      BartE
    • RE: Unable to receive messages after sleep?

      @elmezie after a sleep the radio is not powered on again (sleep is for battery power nodes which normally do no expect message to receive)

      One can wake up the radio again by sending a message e.g. requesting a status or perhaps the current time with gw.requestTime(receiveTime);

      posted in Development
      BartE
      BartE
    • RE: Send heartbeat message from Vera

      @Lior-Rubin What you can do is on your Vera (UI5 but should work on UI7):

      • Create a "Hearthbeat" scene
      • Add a scene "Schedule" on the heartbeat interval you like say: "Interval based: Every 1 hour"
      • On the Luup-tab fill in this command
      luup.call_action("urn:upnp-arduino-cc:serviceId:arduino1", "SendCommand", {radioId="2;255", variableId="VAR_5", value=2}, 98)
      
      • Confirm the new scene
      • Save changes to let restart your Luup engine

      There is no such thing as a I_HEARTBEAT (nor a V_HEARTBEAT) look on this page for the available sub-types (skip the V_ in your variableId-string)

      Your MySensors node (in the example with ID 2) should handle the incoming message with sub-type V_VAR5
      ID 1 (radioID 1) will not work this is reserved for the gateway

      posted in Vera
      BartE
      BartE
    • RE: Array Relay Button Actuator

      @martinhjelmare there is no reason to have that many button checks per millisecond, if you "wait" each while loop the MySensors core has more time to process messages i.s.o. of reading I/O pins especially when your node acts as a repeater. (During a wait the process function is called)
      A person will not notices a button to take 50 i.s.o 10 milliseconds to respond.

      posted in General Discussion
      BartE
      BartE
    • RE: My Slim 2AA Battery Node

      @sensorchecker and @m26872 changing the NRF module did work for me as well.

      I was struggling a lot getting the power consumption down using all the trick and tips as described on the mysensors forum but nothing worked for by battery powered nodes (i have a couple these ).

      I was not able to bring the power consumption down below 2.4 mA (with the NFR mounted) finally i just, for an differnt experiment, i took a "fresh"NRF and just for the fun i measured the current and it was down to 0.05 mA for no reason. They came from the same batch.

      My theory now is that i broke the first radio module during programming of the node, although the FTDI serial module is in 3.3v mode it still measures around 4.5 volt. So the voltage might has damaged my NRF radio a bit (it still communicates).

      posted in My Project
      BartE
      BartE
    • RE: Child_ID

      @lafleur You can use the 'sensor' member

      void incomingMessage(const MyMessage &message) 
      {
        if (message.sensor == Child_ID && message.type==V_VAR1) 
        {
          unsigned long gwPulseCount=message.getULong();
        }
      }
      
      posted in Development
      BartE
      BartE
    • RE: "Choose the Serial Port" error with MySensors and RFXtrx433?

      @Magnus just a wild guess.

      Did you try to compile the MySensors GW with baudrate set to 38400 so they both use the same baudrate?

      posted in Vera
      BartE
      BartE
    • RE: Guide for connecting several small RGB 5050 ledstrips?

      @Cliff-Karlsson if you want to dim the strips it requires PWM (pulse width modulation) pens and the nano only has 6 of them (D3, D5, D6, D9, D10 and D11)
      D11 and D10 are occupied by the MySensors radio leaving 4 to controll the LED strip.
      So you will requires either:

      • list itema different Arduino (the MEGA has 15 PWM's)
      • or using ShiftPWM (http://www.elcojacobs.com/shiftpwm/)
      • or use 4 Arduinos
      posted in General Discussion
      BartE
      BartE
    • RE: RFID Garage door opener

      @codergirl56 Oke i will give it a try:

      Basic IO pin set up

      void setup() {
              Serial.begin(BAUD);     // Initialize serial communications with the PC
              pinMode(GARAGEPIN, OUTPUT);     // Initialise in/output ports
              pinMode(SECONDRELAY, OUTPUT);     // Initialise in/output ports
      

      This part initializes the SPI I/O pins used by the RFID reader so it release the SPI bus for thr NFR radio

              // Make sure MFRC will be disabled on the SPI bus
              pinMode(RST_PIN, OUTPUT);     
              digitalWrite(RST_PIN, LOW);
              pinMode(SS_PIN, OUTPUT);     
              digitalWrite(SS_PIN, LOW);
      

      Init LED and button I/O-pin

              pinMode(LED_PIN, OUTPUT);
              digitalWrite(LED_PIN, LOW);
              // Setup the button
              pinMode(SWITCH_PIN, INPUT_PULLUP);
      
              // After setting up the button, setup debouncer
              debouncer.attach(SWITCH_PIN);
              debouncer.interval(5);
      

      Init radion module

              // Init mysensors library
              gw.begin(incomingMessage, 5);
              gw.sendSketchInfo("RFID Garage", "1.2"); delay(RF_INIT_DELAY);
              
              // Register all sensors to gw (they will be created as child devices)
              gw.present(CHILD_ID_LOCK, S_LOCK);      delay(RF_INIT_DELAY);
              gw.present(CHILD_ID_LOCK2, S_LOCK);      delay(RF_INIT_DELAY);
              gw.present(CHILD_ID_ALARM, S_MOTION);   delay(RF_INIT_DELAY);
      

      Read eeprom settings

              recallEeprom();
      

      nit SPI bus for MFRC RFID sensor

              SPI.begin();            // Init SPI bus
              mfrc522.PCD_Init();     // Init MFRC522
              ShowReaderDetails();            // Show details of PCD - MFRC522 Card Reader details
      
              gw.send(lockArmMsg.set(armed));
              Serial.println(F("Init done..."));
      }
      
      void loop() {
              timer++;
              delay(HEARTBEAT);
              gw.process();
              debouncer.update();
      
              // Get the update value
              int switchValue = debouncer.read();
              if (switchValue != oldSwitchValue) {
                // Send in the new value
                Serial.print (F("Switch "));
                Serial.println (switchValue);
                
                if (switchValue && programmode) {
                     lastTime     = millis() / 1000;
                }
                
                if (!switchValue && programmode && lastTime > 0) {
                     if ( (millis() / 1000) - lastTime > 3) {
                          Serial.println(F("Reset all cards"));  
                          countValidCards  = 0;
                          blinkFast(50);
                     } else {
                        Serial.println(F("Program off"));  
                        digitalWrite(LED_PIN, LOW);
                        programmode = false;
                        
                        storeEeprom();
                     }
                }
                
                if (!switchValue)   {
                    programTimer = 0;
                }
                oldSwitchValue = switchValue;
              }
              
              if (programmode && ((timer % (ONE_SEC / HEARTBEAT)) == 0 ))  {
                  ledon = !ledon;
                  digitalWrite(LED_PIN, ledon);
                  programTimer++;
      
                  // Stop program mode after 20 sec inactivity
                  if (programTimer > PROG_WAIT)  {
                     programmode = false;
                     digitalWrite(LED_PIN, false);
                     Serial.println(F("Program expired"));  
                  }
              }
              
              if ((timer % (200 / HEARTBEAT)) == 0 )   {
                   // Look for new cards
                   if ( ! mfrc522.PICC_IsNewCardPresent()) {
                        if (releasecnt > 0)   {
                            releasecnt--;
                            if (!releasecnt)  {
                                olduid.size = 0;
                                Serial.println(F("release"));
                            }
                          }
                  return;
                  }
                  releasecnt = 5;
      

      Check if a RFID card is held at the RFID reader if not: skip the rest and start over with loop()

                 // Select one of the cards
                 if ( ! mfrc522.PICC_ReadCardSerial()) {
                    return;
                 }
          
                 // Dump debug info about the card; PICC_HaltA() is automatically called
                 //mfrc522.PICC_DumpToSerial(&(mfrc522.uid));
      

      Check if this card is the same as the previous loop if not enter the IF loop

                 if (!olduid.size || !sameUid(&(mfrc522.uid), &olduid))  {
                      ShowCardData(&(mfrc522.uid));
                      copyUid(&(mfrc522.uid), &olduid);
                      if ( isValidCard(&olduid) )   {
                           OpenDoor(programmode);
                      } else  {
      

      Check if the master card was presented and the button was pressed enter program mode

                         if (sameUid(&(mfrc522.uid), &masterkey)) {
                             // Only switch in program mode when mastercard is found AND the program button is pressed
                             if (switchValue)  {
                               Serial.println(F("Program mode"));
                               programmode = true;
                               programTimer = 0;
                               lastTime     = 0;
                             } else {
                               OpenDoor2(programmode);
                             }
                         } else {
      

      If not the master card and this card in not known and we're in program mode add this as a new card

                             if (programmode) {
                               Serial.println(F("new card"));
                               programTimer = 0;
                               
                               if (countValidCards < MAX_CARDS)
                               {
                                  // Add card to list...
                                  copyUid(&(mfrc522.uid), &validCards[countValidCards]);
                                  countValidCards++;
                                  blinkFast(15);
                               }
                             } else {
                               Serial.println(F("Invalid card"));
                               if (armed) {
                                  gw.send(wrongMsg.set(1));
                                  delay(2000);
                                  gw.send(wrongMsg.set(0));
                               }
                             }
                         }
                      }
                 }
              }
      }
      

      These are support functions

      void ShowCardData(MFRC522::Uid* uid) 
      {
          Serial.print(F("Card UID:"));
          for (byte i = 0; i < uid->size; i++) {
              if(uid->uidByte[i] < 0x10) {
                  Serial.print(F(" 0"));
              } else {
                  Serial.print(F(" "));
                      }
              Serial.print(uid->uidByte[i], HEX);
          } 
          Serial.println();
      }
      
      void copyUid(MFRC522::Uid* src, MFRC522::Uid* dest)
      {
          dest->size = src->size;
          dest->sak  = src->sak;
          
          for (byte i = 0; i < src->size; i++) {
          dest->uidByte[i] = src->uidByte[i];
          }
      }
      
      bool sameUid(MFRC522::Uid* old, MFRC522::Uid* check)
      {
          if (old->size != check->size) {
             return false;
          }
          for (byte i = 0; i < old->size; i++) {
              if (old->uidByte[i] != check->uidByte[i]) {
                  return false;
              }
          }
          return true;
      }
      
      bool isValidCard(MFRC522::Uid* uid)
      {
            for (byte i = 0; i < countValidCards; i++)  {
                if (validCards[i].size != uid->size)  {
                    break;
                }
                for (int j = 0; j < uid->size; j++) {
                    if (validCards[i].uidByte[j] != uid->uidByte[j])  {
                        break;
                    }
                    if (j == (uid->size - 1)) {  
                        return true;
                    }
                }
            }
            return false;
      }
      
      
      void storeEeprom()
      {
          byte address = 0;
          gw.saveState(address++, countValidCards);
          
          for (byte i = 0; i < countValidCards; i++) {
             gw.saveState(address++, validCards[i].size);
             for (byte j = 0; j < 10; j++) {
                gw.saveState(address++, validCards[i].uidByte[j]);
             } 
          }
      }
      
      void recallEeprom()
      {
          byte address = 0;
          
          countValidCards = gw.loadState(address++);
          if (countValidCards > MAX_CARDS) {
             Serial.println(F("Not a valid EEPROM reading set to default"));
             countValidCards = 0;
             storeEeprom();
             return;
          }
          
          for (byte i = 0; i < countValidCards; i++)  {
             validCards[i].size = gw.loadState(address++);
             for (byte j = 0; j < 10; j++)  {
                validCards[i].uidByte[j] = gw.loadState(address++);
             } 
          }
        
      }
      
      void blinkFast(int times)
      {
          for (int i = 0; i < times; i++) { 
             ledon = !ledon;
             digitalWrite(LED_PIN, ledon);
             delay(100);
          }
      }
      
      void OpenDoor(bool fakeOpen)
      {
          Serial.println(F("Open door!"));
          gw.send(lockMsg.set(false));
          
          if (!fakeOpen) { 
            digitalWrite(LED_PIN, HIGH);
            digitalWrite(GARAGEPIN, HIGH); 
          }
          delay(1000);
          
          if (!fakeOpen) { 
            digitalWrite(GARAGEPIN, LOW); 
            digitalWrite(LED_PIN, LOW);
          }
          
          gw.send(lockMsg.set(true));
      }
      
      void OpenDoor2(bool fakeOpen)
      {
          Serial.println(F("Open door 2!"));
          gw.send(lock2Msg.set(false));
          
          if (!fakeOpen) { 
            digitalWrite(LED_PIN, HIGH);
            digitalWrite(SECONDRELAY, HIGH); 
          }
          delay(1000);
          
          if (!fakeOpen) { 
            digitalWrite(SECONDRELAY, LOW); 
            digitalWrite(LED_PIN, LOW);
          }
          
          gw.send(lock2Msg.set(true));
      }
      
      void ShowReaderDetails() {
          // Get the MFRC522 software version
          byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg);
          Serial.print(F("MFRC522 Software Version: 0x"));
          Serial.print(v, HEX);
          if (v == 0x91) {
              Serial.print(F(" = v1.0"));
              } else if (v == 0x92) {
              Serial.print(F(" = v2.0"));
              } else {
              Serial.print(F(" (unknown)"));
              }
          Serial.println("");
          
              // When 0x00 or 0xFF is returned, communication probably failed
          if ((v == 0x00) || (v == 0xFF)) {
              Serial.println(F("WARNING: Communication failure, is the MFRC522 properly connected?"));
          }
      }
      
      
      void incomingMessage(const MyMessage &message) 
      {
         if (message.type == V_LOCK_STATUS) {
           // Change relay state
           if (!message.getBool())  {
              switch (message.sensor)
              {
                 case CHILD_ID_LOCK:
                    OpenDoor(false);
                    break;
                 case CHILD_ID_LOCK2:
                    OpenDoor2(false);
                    break;
              }
           }
        
           // Write some debug info
           Serial.print(F("Lock:  "));
           Serial.print(message.sensor);
           Serial.print(F(" status: "));
           Serial.println(message.getBool());
         }
         else 
         {
           if (message.type == V_ARMED)  {
             // Change relay state
             armed = message.getBool();
        
             // Write some debug info
             Serial.print(F("Arm status: "));
             Serial.println(message.getBool());
           }
           else
           {
             // Write some debug info
             Serial.print(F("Incoming msg type: "));
             Serial.print(message.type);
             Serial.print(F(" id: "));
             Serial.print(message.sensor);
             Serial.print(F(" content: "));
             Serial.println(message.getInt());
           }
         }
      }
      posted in My Project
      BartE
      BartE
    • RE: 433MHz Motion Sensor sketch

      @mfalkvidd yes you're right i will update my post

      posted in Development
      BartE
      BartE
    • RE: 💬 Dimmable LED Actuator

      @thazlett144 can't help to make a few comments on your sketch (sorry)

      The led the array start from 0 and prevent the double pin declaration simply subtract one on usage so
      this LED_Pin[ledid] becomes this LED_Pin[ledid-1]

      please do use wait() instead of delay(), delay is blocking MySensors communication

          // hek comment: Is this really nessesary?
          send( dimmerMsg.set(currentLevel) );
      

      Answer: Yes, controllers like Vera want feedback about the new dimlevel

      posted in Announcements
      BartE
      BartE
    • RE: Relais sketch, auto switch on again after x seconds

      @Corvl yes you should be able to upgrade.byt you have top upgrade the gateway aswel.

      It is quicker to solve the compile errors:

      Do note that C in case sensitive so

      • change RELAY_Off to RELAY_OFF on line 28 and 47
      • change RELAY_On to RELAY_ON on line 31 and 50

      Since you use the old library you also should change wait to gw.wait on line 30 and 49

      That should fix the compiler error.
      I think the second gw.wait should also be 5000 iso 500 if you want to wait 5 seconds also.

      As a general comment, when programming C it is general practice to use indents for beter readability of the code so please add some whitespace in front of the added lines

      posted in General Discussion
      BartE
      BartE
    • RE: RFID Garage door opener

      @Chakkie sorry for the slow response (i was on a pre summer holiday)

      Thx for analyzing this report. The fix you did made is not what i meant with program expired.

      The idea is that you start program mode by pressing the program button and holding the master card.
      And now one can add one or more new RFID cards and when your oke press the program button for a short period to END the program mode and store the new cards.

      If you wait too long the program mode will expire and the new cards are NOT stored. Off course you can change this behavior by adding this line as you suggested.

      posted in My Project
      BartE
      BartE
    • RE: Round-about way to make a sleepable relay node

      @dsiee This answer is to explain the basics for node 2 node communications

      To respond to node 2 node requests the incomingMessage() function needs to be changed in such a way that it responds to requests
      In this example, for the answering node, one can request for temperature, humidity and pressure

      void incomingMessage(const MyMessage &message) 
      {
         //  Check for incoming node to node request
         if (mGetCommand(message) == C_REQ) {
               MyMessage msg;
               mSetCommand(msg, C_SET);
               msg.setType(message.type);
               msg.setSensor(message.sensor);
               msg.setDestination(message.sender);
               bool bHandled = true;
               switch (message.sensor) {
                 case CHILD_ID_HUM:
                     msg.setType(V_HUM);
                     msg.set(lastHum, 1);
                     break;
                     
                 case CHILD_ID_TEMP:
                     msg.setType(V_TEMP);
                     msg.set(lastTemp, 1);
                     break;
      
                 case CHILD_ID_BARO:
                     msg.setType(V_PRESSURE);
                     msg.set(lastPressure, 0);
                     break;
      
                default:
                     bHandled = false; 
                     break;
               }
               if (bHandled) {
                   gw.send(msg); 
               }
          } else {
             // do normal message handling stuff
             switch  (message.type) {
                 case V_STATUS:
                     // Do something useful
                     break;
          }
      }
      

      With this call one can perform the request

      gw.request( TEMP_SENS_ID,  V_TEMP, WEATHER_NODE_ID);
      

      And the requesting node should hande incoming data in incomingMessage()

      void incomingMessage(const MyMessage &message) {
         // We only expect one type of message from controller. But we better check anyway.
         if (message.isAck()) {
             Serial.println(F("GW ack"));
         }
        switch (message.type) {
      	case V_TEMP:
      	   // Write some debug info
      	   Serial.print(F("Temp received: "));
      	   Serial.print(message.sensor);
      	   Serial.print(F(" : "));
      	   Serial.println((int)message.getFloat());
      	   break;
      
      	case V_HUM:
      	   // Write some debug info
      	   Serial.print(F("Humidity received: "));
      	   Serial.print(message.sensor);
      	   Serial.print(F(" : "));
      	   Serial.println(message.getInt(), HEX);
      	   break;
      
      	case V_PRESSURE:
      	   // Write some debug info
      	   Serial.print(F("Pressure received: "));
      	   Serial.print(message.sensor);
      	   Serial.print(F(" : "));
      	   Serial.println(message.getInt());
      	   break;
         }
      }
      
      posted in Development
      BartE
      BartE
    • RE: 3 + 4 way switch with a relay

      @Sefi-Ninio What about the wiring this would look like this:
      0_1456000601063_3way4wayRelay.png

      @mfalkvidd is right you can use an mobile phone charger or an USB 230v adapter plug like this

      Of course a real 230v coil relay this this

      posted in Hardware
      BartE
      BartE
    • RE: MySensors booth at Eindhoven Maker Faire!

      @Yveaux That is more or less in my backyard so i need to visit the booth!
      Any help needed?

      posted in Announcements
      BartE
      BartE
    • RE: Car Aux Battery Monitor

      @Boots33 No i did use a standard Arduino Nano not a low power one.

      It is monitoring a caravan mover battery with a 105 Ah capacity, i think it will last during the winter on one load 😄

      posted in My Project
      BartE
      BartE
    • RE: how to read other device status with arduino?

      @leeoz there are two ways to achieve this

      1. The easy way:
        Each time the temperature is changed in arduino1 and the controller is updated with a
        message like this:
      gw.send(msgTemp.set(((float)temperature / 10.0), 1)); 
      

      Also send a message to arduino2 something like this:
      arduino1 code:

      // This can be the sensor ID on arduino2 device #12 (but if you do not check each integer between 1-254 will do)
      #define MYSENSOR_TEMP_LCD  1
      MyMessage msgTempNode2 (MYSENSOR_TEMP_LCD,  V_TEMP);  
      
      void loop ()
      {
          gw.process();
          ... do stuff
         if (oldtemperature  != temperature)
         {     // inform the gateway we have a new temp.
              gw.send(msgTemp.set(((float)temperature / 10.0), 1)); 
          
              gw.wait(100); // give the gateway some time to process the 1ste message
      
             // inform our LCD slave node also about the temp. change
             msgTempNode2.setDestination(12); // This is the node ID on arduino2 
             gw.send(msgTempNode2.set(((float)temperature / 10.0), 1),; 
             oldtemperature  = temperature;
        }
      
          ... do some more stuff
      }
      

      The LCD arduino should handle the incoming TEMP message, arduino2 code:

      void incomingMessage(const MyMessage &message) {
         if (message.isAck()) {
              Serial.println(F("GW ack"));
         }
         switch (message.type) {
            case V_TEMP:
                Serial.print("New temperature received : ");
                Serial.println(message.getFloat());
                ... do some stuff to update your LCD screen
                break; 
        }
      }
      

      2)The second more complex way is to request the temperature from arduino2 to arduino1
      arduino1 code:

      // This can be the sensor ID on arduino2 device #12 (but if you do not check each integer between 1-254 will do)
      #define MYSENSOR_TEMP_LCD  1
      MyMessage msgTempNode2 (MYSENSOR_TEMP_LCD,  V_TEMP);  
      
      void loop ()
      {
          gw.process();
          ... do stuff
         if (oldtemperature  != temperature)
         {     // inform the gateway we have a new temp.
              gw.send(msgTemp.set(((float)temperature / 10.0), 1)); 
              // Store the temp.
              oldtemperature  = temperature;
        }
         ... do more stuff
      }
      
      void incomingMessage(const MyMessage &message) {
          if (mGetCommand(message) == C_REQ) {
               MyMessage answerMsg;
               Serial.print("Incoming request for sensor: ");
               Serial.println(message.sensor);
               mSetCommand(answerMsg, C_SET);
               answerMsg.setSensor(message.sensor);
               answerMsg.setDestination(message.sender);
               switch (message.sensor) {
                 case MYSENSOR_TEMP:
                     answerMsg.setType(V_TEMP);
                     gw.send(answerMsg.set((float)(oldtemperature/ 10.0), 1));
                     break;
              }
          } else {
              if (message.isAck()) {
                  Serial.println(F("GW ack"));
              }
              switch (message.type) {
                  ... handle other messages
              }
         }
      }
      

      arduino2 code:

      void loop ()
      {
        gw.process();
          ... do stuff
         if (time_to_poll_for_temp())
         {     // Request for temperature
               gw.request(MYSENSOR_TEMP, V_TEMP, 12);   // This is the node ID on arduino2 
        }
      }
      
      void incomingMessage(const MyMessage &message) {
         if (message.isAck()) {
              Serial.println(F("GW ack"));
         }
         switch (message.type) {
            case V_TEMP:
                Serial.print("New temperature received : ");
                Serial.println(message.getFloat());
                ... do some stuff to update your LCD screen
                break; 
        }
      }
      ``
      posted in Development
      BartE
      BartE
    • RE: 💬 MySensors @Eindhoven Maker Fair 2017 2-3 September

      Yes we will be there soon and make some pictures!

      posted in Announcements
      BartE
      BartE
    • RE: Cobine working DHT22 and LDR with a RelayWithButtonActuator

      @Dick
      laatste:163: error: 'msg' was not declared in this scope

      msg should become msgLight

      gw.send(msgLight.set(state ? false : true), true); // Send new state and request ack back
      

      and move one } just below this line

      gw.wait(HEARTBEAT); //sleep a bit
      }
      }
      

      to the very end of you sketch

      posted in Development
      BartE
      BartE
    • RE: Dimmable LED kitchen light (Arduino, APDS-9960, RGBWW led)

      @mfalkvidd a video with cool 8 bit music 🙂 nice

      posted in OpenHardware.io
      BartE
      BartE
    • RE: Please help

      Hi @pesh000, couple of remarks at your sketch

      1. Did you try the RCSwitch code with out any MySensor stuff so for example the SendDemo sketch with for your garage door the correct ID and pin settings? And did the garage door open/close?

      2. Why declaring 2 debouncer variables but still using digitalRead? Look at the MySensors RelayWithButtonActuator example for debouncer examples

      3. Why using hard coded numbers in the incomingMessage switch to determine which sensor did broadcast the V_LIGHT message while you have CHILD_ID_RELAY1, CHILD_ID_RELAY2 and CHILD_ID_RELAY3 declared?

      4. better use gw.wait(1000); in stead g delay(1000); during gw.wait() MySensors messages keep being processed. Even better do not use wait() functions or very short ones to keep your sketch responsive to triggers

      And last but not least it will help if you can post some debug logging from your sketch. I hope these comments will help you to debug , good luck

      posted in Troubleshooting
      BartE
      BartE
    • RE: Extra command message type for local data requests

      OK i did make a prototype implementation using the V_CUSTOM message type.
      This works for Vera only.

      I had to change only one file: L_Arduino.lua
      The function starting on line 244 has te be extened with this if statement:

      -- Handle Local Request variables	
      if (varType == "CUSTOM") then
      	local bit         = require("bit")
              local varReqIndex = bit.band(tonumber(value), 0xFF);
              local varVeraId   = bit.rshift(tonumber(value), 8);
      	local varReqType  = tVarLookupNumType[varReqIndex]
      	local varReq      = tVarTypes[varReqType]
                              
      	if (varReq[2] ~= nil) then 
      		log("Local request '" .. varReq[3] .. "' from Device ID: ".. varVeraId .. " sensor type '" .. varReqType .. "'")
      		local localValue = luup.variable_get(varReq[2], varReq[3], varVeraId)
      		if (localValue ~= nil) then
      			-- Send variable value to actuator
      			sendRequestResponse(nodeId .. ";" .. childId, varReqType, localValue)
      		end
      	end	
      else
      

      The complete function will then look like this:

      local function setVariable(incomingData, childId, nodeId)
      	if (childId ~= nil) then
      		-- Set variable on child sensor.
      		local index = tonumber(incomingData[5]);
      		local varType = tVarLookupNumType[index]
      		local var = tVarTypes[varType]
      		local value = incomingData[6]
      		local timestamp = os.time()
      
                      -- Handle Local Request variables	
      		if (varType == "CUSTOM") then
      			local bit         = require("bit")
                              local varReqIndex = bit.band(tonumber(value), 0xFF);
                              local varVeraId   = bit.rshift(tonumber(value), 8);
      			local varReqType  = tVarLookupNumType[varReqIndex]
      			local varReq      = tVarTypes[varReqType]
                              
      		        if (varReq[2] ~= nil) then 
      				log("Local request '" .. varReq[3] .. "' from Device ID: ".. varVeraId .. " sensor type '" .. varReqType .. "'")
      				local localValue = luup.variable_get(varReq[2], varReq[3], varVeraId)
      				if (localValue ~= nil) then
      					-- Send variable value to actuator
      					sendRequestResponse(nodeId .. ";" .. childId, varReqType, localValue)
      				end
      			end	
      
      		elseif (var[2] ~= nil) then 
      			log("Setting variable '".. var[3] .. "' to value '".. value.. "'")
      			setVariableIfChanged(var[2], var[3], value, childId)
      		
      			-- Handle special variables battery level and tripped which also
      			-- should update other variables to os.time()
      			if (varType == "TRIPPED" and value == "1") then
      				local variable = tVeraTypes["LAST_TRIP"]
      				setVariableIfChanged(variable[2], variable[3], timestamp, childId)
      			else
      				local variable = tVeraTypes["LAST_UPDATE"]
      				setVariableIfChanged(variable[2], variable[3], timestamp, childId)
      			end
      		end
      
      		-- Always update LAST_UPDATE for node	
      		if (nodeId ~= nil) then
      			local nodeDevice = childIdLookupTable[nodeId .. ";" .. NODE_CHILD_ID] 
      			setLastUpdate(nodeDevice)
      		end
      	end
      end
      

      Now the Vera HA-contoller response on V_CUSTOM messages.

      Use the feature in a MySensors node:

      void requestValue(byte type, unsigned int id)
      {
           MyMessage msgRequest(1, V_CUSTOM);
           unsigned long msgData;
           msgData = type + ((unsigned long)id * 0x100); 
           send(msgRequest.set(msgData));
      }
      
      void loop()
      {
           // Request the status from Vera Device 4
           requestValue(V_STATUS,  4);
       
          // Request the dimn level  from Vera Device 20
          requestValue(V_LEVEL, 20);
         
         // etc..  
      }
      

      Make sure you can handle the incoming messages

      void receive(const MyMessage &message)
      {
      	if (message.type==V_STATUS) {
      		Serial.print(" New value: ");
      		Serial.println(message.getBool());
      	}
             if (message.type==V_LEVEL) {
      		Serial.print(" New value: ");
      		Serial.println(message.getByte());
      	}
             if (message.type==V_TEMP) {
      		 Serial.print(" New value: ");
      		Serial.println(message.getFloat());
      	}
      }
      

      If you need the same value type from different Device a different sensor id can be used, the requestValue will then look like this:

      void requestValue(byte type, unsigned int id, byte sensorid)
      {
           MyMessage msgRequest(sensorid, V_CUSTOM);
           unsigned long msgData;
           msgData = type + ((unsigned long)id * 0x100); 
           send(msgRequest.set(msgData));
      }
      

      In the receive function "message.sensor" can be used to determine for which device a request was made

      posted in Feature Requests
      BartE
      BartE
    • RE: How to find out if message was successfully delivered?

      @boozz and @flopp what you check here is that the message successfully was broadcast-ed to the next node.
      This can be either the gateway or a repeater node.

      With the reception of an acknowledge message you are sure that the original message was delivered at the gateway (and back).

      posted in Development
      BartE
      BartE
    • RE: Combine DimmableLEDActuator sketch with RelayActuator Sketch

      @rsaeful
      better use gw.wait() i.s.o. of delay. during the gw.wait() you are still receiving and sending MyS messages. delay is blocking

      So the function will look like this

      void fadeToLevel( int toLevel ) {
        int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1;
          while ( currentLevel != toLevel ) {
           currentLevel += delta;
           analogWrite( LED_PIN, (int)(currentLevel * 2.55));
           gw.wait( FADE_DELAY );
        }
      }
      
      posted in Troubleshooting
      BartE
      BartE
    • RE: How to find out if message was successfully delivered?

      @flopp

      Here is a reliable delivery discussion with more information

      posted in Development
      BartE
      BartE
    • RE: [Solved] Communication from Gateway to Sensor node not working

      @palande.vaibhav
      i think the answer is in the code

        // sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater)
         sleep(conversionTime);
      

      Replace sleep(); by wait();

      During a sleep the GW does not receives the message acknowledge and thus claims the broadcast did fail.

      posted in Troubleshooting
      BartE
      BartE
    • RE: multiple buttons on one analog pin arduino

      @daniel.stancu you can do something like this

      This examples servers 10 switches with 10 relays

      /**
         The MySensors Arduino library handles the wireless radio link and protocol
         between your home built sensors/actuators and HA controller of choice.
         The sensors forms a self healing radio network with optional repeaters. Each
         repeater and gateway builds a routing tables in EEPROM which keeps track of the
         network topology allowing messages to be routed to nodes.
      
         Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
         Copyright (C) 2013-2015 Sensnology AB
         Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
      
         Documentation: http://www.mysensors.org
         Support Forum: http://forum.mysensors.org
      
         This program is free software; you can redistribute it and/or
         modify it under the terms of the GNU General Public License
         version 2 as published by the Free Software Foundation.
      
       *******************************
      
         REVISION HISTORY
         Version 1.0 - Henrik Ekblad
      
         DESCRIPTION
         Example sketch showing how to control physical relays.
         This example will remember relay state after power failure.
         http://www.mysensors.org/build/relay
      */
      
      // 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
      
      #include <MySensors.h>
      
      #define NUMBER_OF_RELAYS 10   // Total number of attached relays and switches
      
      unsigned int  relay_pins[NUMBER_OF_RELAYS] = { 1, 2, 3, 4, 5, 6, 7, 8, A1, A2 };
      #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
      
      MyMessage  msg(0,  V_LIGHT);
      
      #define BUTTON_PIN   A0
      #define NO_BUTTON    255
      // The followinging are interrupt-driven keypad reading functions
      //  which includes DEBOUNCE ON/OFF mechanism, and continuous pressing detection
      #define NUM_BUTTONS     NUMBER_OF_RELAYS
      //keypad debounce parameter
      #define DEBOUNCE_MAX 6
      #define DEBOUNCE_ON  4
      #define DEBOUNCE_OFF 2
      
      // adc preset value, represent top value,incl. noise & margin,that the adc reads, when a key is pressed
      // set noise & margin = 30 (0.15V@5V)
      unsigned int  adc_key_val[NUM_BUTTONS] = { 50, 150, 200, 250, 300, 450, 500, 550, 600, 650 };
      
      
      // debounce counters
      byte button_count[NUM_BUTTONS];
      // button status - pressed/released
      byte button_status[NUM_BUTTONS];
      // button on flags for user program
      byte button_flag[NUM_BUTTONS];
      
      byte lastButtonPressed = NO_BUTTON;
      
      
      void before()
      {
        for (int sensor = 0; sensor < NUMBER_OF_RELAYS; sensor++) {
          // Then set relay pins in output mode
          pinMode(relay_pins[sensor], OUTPUT);
          // Set relay to last known state (using eeprom storage)
          digitalWrite(relay_pins[sensor], loadState(sensor) ? RELAY_ON : RELAY_OFF);
        }
        pinMode(BUTTON_PIN, INPUT);
      }
      
      void setup()
      {
        // reset button arrays
        for (byte i = 0; i < NUM_BUTTONS; i++)
        {
          button_count[i]  = 0;
          button_status[i] = 0;
          button_flag[i]   = 0;
        }
      }
      
      void presentation()
      {
        // Send the sketch version information to the gateway and Controller
        sendSketchInfo("Relay 32", "1.0");
      
        for (int sensor = 0; sensor < NUMBER_OF_RELAYS; sensor++) {
          // Register all sensors to gw (they will be created as child devices)
          present(sensor + 1, S_BINARY);
        }
      }
      
      
      void loop()
      {
        byte button = buttonPressed();
      
        // Check if there was a change of buttons presses
        if (button != lastButtonPressed)  {
          // YES we detected a change, only response when buttons was released
          if (button == NO_BUTTON) {
            msg.sensor = button + 1;
            send(msg.set(loadState(button) ? "0" : "1") );
          }
          lastButtonPressed = button;
        }
      
        wait(10);
      }
      
      
      char buttonPressed()
      {
        for (byte i = 0; i < NUM_BUTTONS; i++)
        {
          if (button_flag[i] != 0) {
            button_flag[i] = 0;
            return i;
          }
        }
        return NO_BUTTON;
      }
      
      // Convert ADC value to key number
      char get_key(unsigned int input)
      {
        for (int k = 0; k < NUM_BUTTONS; k++)
        {
          if (input < adc_key_val[k]) {
            return k;
          }
        }
        return -1;    // No valid key pressed
      }
      
      void update_adc_key()
      {
        unsigned int adc_key_in;
        char key_in;
        byte i;
      
        adc_key_in = analogRead(BUTTON_PIN);
        Serial.println(adc_key_in); // For debug only
        key_in = get_key(adc_key_in);
      
        for (i = 0; i < NUM_BUTTONS; i++)
        {
          if (key_in == i) {
            //one key is pressed
            if (button_count[i] < DEBOUNCE_MAX) {
              button_count[i]++;
              if (button_count[i] > DEBOUNCE_ON) {
                if (button_status[i] == 0) {
                  button_flag[i] = 1;
                  button_status[i] = 1; //button debounced to 'pressed' status
                }
              }
            }
          }
          else // no button pressed
          {
            if (button_count[i] > 0) {
              button_flag[i] = 0;
              button_count[i]--;
              if (button_count[i] < DEBOUNCE_OFF) {
                button_status[i] = 0;   //button debounced to 'released' status
              }
            }
          }
        }
      }
      
      
      void receive(const MyMessage &message)
      {
        // We only expect one type of message from controller. But we better check anyway.
        if (message.type == V_STATUS) {
          // Change relay state
          digitalWrite(relay_pins[message.sensor - 1], message.getBool() ? RELAY_ON : RELAY_OFF);
          // Store state in eeprom
          saveState(message.sensor - 1, message.getBool());
          // Write some debug info
          Serial.print("Incoming change for sensor:");
          Serial.print(message.sensor);
          Serial.print(", New status: ");
          Serial.println(message.getBool());
        }
      }
      

      You have to connect the switches likes this, the value for R2 - Rx resistors around 100 ohms and 10k for R1.
      0_1498156940390_mutliple_switches.png

      With the Serial.println debug statement one has to determine the correct analog values for the adc_key_val array (start with the lowest value first) by pressing the keys one by one, add approx 30 to the average values per button you see in the serial monitor too have some margin.

      posted in Development
      BartE
      BartE
    • RE: cannot compile new MQTT GW sketch

      @siod this line is missing

      #include <SPI.h>
      

      You need to add this line before these includes

      #include <Ethernet.h>
      #include <MySensors.h>
      
      posted in Troubleshooting
      BartE
      BartE
    • RE: RGB Leds Light - Mood Light

      @OliverDog here is a link to such a sketch (https://forum.mysensors.org/topic/2160/my-mysensors-rgbw-plug-in-has-an-init-problem)

      posted in Development
      BartE
      BartE
    • RE: PIR node with interrupts

      @Creaky couple of remarks.

      • use wait i.s.o delay (delay is a blocked call so no MySensor messaging)
      • give the MySensors functions some time after the trigger to process the messages so wait for 200 or 300 milliseconds i.s.o of 50
      • and as stated by @Nca78 beter use the sleep function from MySensors to wait for a interrupt
      posted in Troubleshooting
      BartE
      BartE
    • RE: RGB Leds Light - Mood Light

      Hi @OliverDog , yes this should work

      • Will it work with a single 4 pin RGB LED common cathode instead of a LED strip?
        --> Uncomment this line "#define RGBW 1" to make it three color (RGB) in stead of four (RGBW).

      • Will it work with Home Assistant Controller like a ordinary RGB Light?
        --> Should work with HAC since it presents it self as a RGB module

      • Could it run on batteries?
        --> Yes why not, but please do read some forum posts about what to think about when running mysensors on batteries, there are several of them

      posted in Development
      BartE
      BartE
    • RE: How to set NodeID in 2.1.1

      Just

      #define MY_NODE_ID 5 
      

      Before the line

      #include <MySensors.h> 
      

      Should work fine

      posted in Development
      BartE
      BartE
    • RE: writing a code for 2 relays with 2 buttons and actuators

      @SandeshHs94 The sketch exactly is that: a combination of the relayActuatorWithButton and
      relayActuator.. examples

      This line does several things

      digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
      

      message.getBool() --> gets the "payload of the message" in this case 1=ON or 0=OFF
      message.sensor --> gives the node id for which the message is meant for
      RELAY_1 --> is the first pin definition (for this sketch 3)
      RELAY_ON --> equals pin HIGH
      RELAY_OFF --> equals pin LOW

      digitalWrite(pin, value); --> sets an output pin in this case pin: message.sensor-1+RELAY_1 (so either pin 3 for node 1 or pin 4 for node 2 messages)
      The ? is a short notation for an if statement so when the message.getBool() = 1 the pin is set to HIGH and when 0 the pin is set to LOW

      I'm not sure why you want no "for-loop", but the sketch would look like this example

      /**
       * The MySensors Arduino library handles the wireless radio link and protocol
       * between your home built sensors/actuators and HA controller of choice.
       * The sensors forms a self healing radio network with optional repeaters. Each
       * repeater and gateway builds a routing tables in EEPROM which keeps track of the
       * network topology allowing messages to be routed to nodes.
       *
       * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
       * Copyright (C) 2013-2015 Sensnology AB
       * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
       *
       * Documentation: http://www.mysensors.org
       * Support Forum: http://forum.mysensors.org
       *
       * This program is free software; you can redistribute it and/or
       * modify it under the terms of the GNU General Public License
       * version 2 as published by the Free Software Foundation.
       *
       *******************************
       *
       * REVISION HISTORY
       * Version 1.0 - Henrik Ekblad
       * 
       * DESCRIPTION
       * Example sketch showing how to control physical relays. 
       * This example will remember relay state after power failure.
       * http://www.mysensors.org/build/relay
       */ 
      
      #include <MySigningNone.h>
      #include <MyTransportNRF24.h>
      #include <MyTransportRFM69.h>
      #include <MyHwATMega328.h>
      #include <MySensor.h>
      #include <SPI.h>
      #include <Bounce2.h>
      
      #define RELAY_1  3  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
      #define RELAY_2  4  // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
      #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 BUTTON_PIN_1 6
      #define BUTTON_PIN_2 7
      
      // NRFRF24L01 radio driver (set low transmit power by default) 
      MyTransportNRF24 radio(RF24_CE_PIN, RF24_CS_PIN, RF24_PA_LEVEL_GW);  
      //MyTransportRFM69 radio;
      // Message signing driver (none default)
      //MySigningNone signer;
      // Select AtMega328 hardware profile
      MyHwATMega328 hw;
      // Construct MySensors library
      MySensor gw(radio, hw);
      
      MyMessage msg1(1, V_LIGHT);
      MyMessage msg2(2, V_LIGHT);
      Bounce debouncer1 = Bounce();
      Bounce debouncer2 = Bounce(); 
      
      void setup()  
      {   
        // Initialize library and add callback for incoming messages
        gw.begin(incomingMessage, AUTO, true);
        // Send the sketch version information to the gateway and Controller
        gw.sendSketchInfo("Relay", "1.0");
      
        // Register all sensors to gw (they will be created as child devices)
        gw.present(1, S_LIGHT);
        // Then set relay pins in output mode
        pinMode(RELAY_1, OUTPUT);   
        // Set relay to last known state (using eeprom storage) 
        digitalWrite(RELAY_1, gw.loadState(1)?RELAY_ON:RELAY_OFF);
        // Setup the button
        pinMode(BUTTON_PIN_1, INPUT);
        // Activate internal pull-up
        digitalWrite(BUTTON_PIN_1, HIGH);
        // After setting up the button, setup debouncer
        debouncer1.attach(BUTTON_PIN_1);
        debouncer1.interval(5);
        
        // Register all sensors to gw (they will be created as child devices)
        gw.present(2, S_LIGHT);
        // Then set relay pins in output mode
        pinMode(RELAY_2, OUTPUT);   
        // Set relay to last known state (using eeprom storage) 
        digitalWrite(RELAY_2, gw.loadState(2)?RELAY_ON:RELAY_OFF);
        // Setup the button
        pinMode(BUTTON_PIN_2, INPUT);
        // Activate internal pull-up
        digitalWrite(BUTTON_PIN_2, HIGH);
        // After setting up the button, setup debouncer
        debouncer2.attach(BUTTON_PIN_2);
        debouncer2.interval(5);
      }
      
      
      void loop() 
      {
        // Alway process incoming messages whenever possible
        gw.process();
        
        if (debouncer1.update() && debouncer1.read()) {
            gw.send(msg1.set( (gw.loadState(1) ? RELAY_OFF : RELAY_ON)), true);
        }
        if (debouncer2.update() && debouncer2.read()) {
            gw.send(msg2.set( (gw.loadState(2) ? RELAY_OFF : RELAY_ON)), true);
        }
      }
      
      void incomingMessage(const MyMessage &message) {
        // We only expect one type of message from controller. But we better check anyway.
        if (message.type==V_LIGHT) {
           // Change relay state
           digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
           // Store state in eeprom
           gw.saveState(message.sensor, message.getBool());
           // Write some debug info
           Serial.print("Incoming change for sensor:");
           Serial.print(message.sensor);
           Serial.print(", New status: ");
           Serial.println(message.getBool());
         } 
      }
      
      posted in Development
      BartE
      BartE