Navigation

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

    BartE

    @BartE

    Contest Winner

    123
    Reputation
    196
    Posts
    2102
    Profile views
    1
    Followers
    0
    Following
    Joined Last Online
    Location the Netherlands Age 50

    BartE Follow
    Contest Winner Plugin Developer

    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

    Latest posts made by BartE

    • RE: Trying to bitbang i2c oled screen, using SSD1306Ascii library

      Hi @alowhum why using the SPI variant?

      This will require only one digital IO pen for the chip select (CS pin) the rest is shared with the radio SPI interface (MOSI, MISO, SCK, CE and power off course)

      posted in Development
      BartE
      BartE
    • RE: Weather data needed for MySensors OLED switch

      @dbemowsk yes there is a list available https://www.wunderground.com/weather/api/d/docs?d=resources/phrase-glossary also showing a list of icons

      posted in Vera
      BartE
      BartE
    • RE: Weather data needed for MySensors OLED switch

      @dbemowsk yes i'm using Weather Underground with my Vera box (http://apps.mios.com/all-reviews.php?id=45)

      Not sure if this work with UI7 (i still use UI5), but the plug in is quite simple so it should work.
      If you create a free weather underground account a API key will be created, i also use the same key for a virtual rain sensor.

      Using this proposed protocol extention : https://forum.mysensors.org/topic/6601/extra-command-message-type-for-local-data-requests will enable you to retrieve information from the Weather plugin, into the MySensors network.

      It is something i'd really like to be added to the core functionality...

      posted in Vera
      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: 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: [Solved] Support for S_MULTIMETER and V_VOLTAGE in Vera

      Does anyone know why the three value are not show in the "data_request?id=lu_sdata" output?

      It only outputs default values:

      {
            "name": "MyMulti",
            "altid": "12;1",
            "id": 346,
            "category": 12,
            "subcategory": -1,
            "room": 0,
            "parent": 64
          },
      

      While i would expect

      {
            "name": "MyMulti",
            "altid": "12;1",
            "id": 346,
            "category": 12,
            "subcategory": -1,
            "room": 0,
            "parent": 64,
            "Impedance": 0,
            "Current": 0,
            "Voltage": 4.89
          },
      

      I'm looking for a solution quite some time now, but I somehow miss a problem.

      posted in Vera
      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: Smartmeters inverted data software corrected?

      @YFandS for some reason these smartmeters use a inverted implementation of the RS232 serial protocol. While Arduino's etc. use the standardized RS232 implementation.

      As far is i known the UART (the "chip" doing the RSR232 decoding fro Arduino) does not supports inverted mode.

      So yes a signal inverter is needed..

      posted in My Project
      BartE
      BartE
    • RE: Need example for setup : RFLink + mySensors Project with NRF24L01

      @knop Fabien tries to explain that the MySensors gateway is a major part of the MySensors-network it not just transmit the messages it actively contributes in, for example assigning node-id's and routing messages.

      While the RFLink gateway only receives MySensors messages,

      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