Hello !
I was inspired by your post and adapt your code to my needs:
- Scene controller on key 10, 11, 12, 13, 14, 15 and 16 (7 scenes possible)
- 4 digit code send as VAR_1 if 4 keys between 1 and 9 have been pushed one after one within 2 seconds
For fun I added a buzzer and a final song is played in case the code is sent.
No control of the code in the sensor, it will be done in the controller (Jeedom).
The code if someone is interested:
/**
* 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.
*
*
* Code modified from AWI
* (http://forum.mysensors.org/topic/3128/slim-node-scene-controller-keypad)
*
* Buzzer code from Sparkfun
* (SparkFun Inventor's Kit / Example sketch 11)
*
*/
/**************************************************************************************/
/* Keyboard sensor. */
/* */
/* Version : 1.5.10 */
/* Date : 17/04/2016 */
/* Modified by : David Carlier */
/**************************************************************************************/
/* --------------- */
/* RST | | A5 */
/* RX | | A4 */
/* TX | ARDUINO | A3 */
/* RFM69 (DIO0) --------- D2 | UNO | A2 */
/* Keyboard SDA --------- D3 | | A1 */
/* Keyboard SCL --------- D4 | ATMEGA 328p | A0 */
/* +3v --------- VCC | | GND --------- GND */
/* GND --------- GND | 8MHz int. | REF */
/* OSC | | VCC --------- +3v */
/* OSC | | D13 --------- RFM69 (SCK) */
/* D5 | | D12 --------- RFM69 (MISO) */
/* D6 | | D11 --------- RFM69 (MOSI) */
/* D7 | | D10 --------- RFM69 (NSS) */
/* LED --------- D8 | | D9 --------- Buzzer */
/* --------------- */
/* */
/* +3v = 2*AA */
/* */
/**************************************************************************************/
#include <SPI.h>
#include <MySensor.h>
#include <MyTransportRFM69.h>
#include <MySigningAtsha204Soft.h>
//Constants for MySensors
#define SKETCH_NAME "Keyboard Sensor"
#define SKETCH_VERSION "1.5.10"
#define CHILD_ID_DIGICODE 0
#define KEYPAD_ID_SCENE 1
#define CHILD_ID_VOLTAGE 2
#define SDA_PIN 3
#define SCL_PIN 4
#define LED_PIN 8
#define BUZZER_PIN 9
#define BUZZ_FREQ_KEY 350
#define BUZZ_TIME_KEY 100
#define BUZZ_FREQ_ERROR 75
#define KEYBOARD_SIZE 16
#define MAX_SCENE 7
#define BATTERY_FULL 3143 // 2xAA usually gives 3.143V when full
#define BATTERY_ZERO 2340 // 2.34V limit for 328p at 8MHz
//Length must equal the total number of notes and spaces
const byte songLength = 18;
//Notes is an array of text characters corresponding to the notes
//in your song. A space represents a rest (no tone)
char notes[] = "cdfda ag cdfdg gf "; // a space represents a rest
//Beats is an array of values for each note and rest.
//A "1" represents a quarter-note, 2 a half-note, etc.
//Don't forget that the rests (spaces) need a length as well.
int beats[] = {1,1,1,1,1,1,4,4,2,1,1,1,1,1,1,4,4,2};
//The tempo is how fast to play the song.
//To make the song play faster, decrease this value.
int tempo = 113;
//Misc. variables
unsigned long WAITING_TIME = 2000; //Waiting time for key pressing
boolean keyState[KEYBOARD_SIZE];
//Construct MySensors library
MySigningAtsha204Soft signer;
MyHwATMega328 hw;
MyTransportRFM69 transport;
MySensor node(transport, hw, signer);
MyMessage msgCode(CHILD_ID_DIGICODE, V_VAR1);
MyMessage msgSceneOn(KEYPAD_ID_SCENE, V_SCENE_ON);
MyMessage msgSceneOff(KEYPAD_ID_SCENE, V_SCENE_OFF);
MyMessage msgVolt(CHILD_ID_VOLTAGE, V_VOLTAGE);
/**************************************************************************************/
/* Initialization */
/**************************************************************************************/
void setup()
{
//Get time (for setup duration)
#ifdef DEBUG
unsigned long startTime = millis();
#endif
//Setup buzzer and LED pins
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
blinkLedFastly(3);
//Set keyboard pin
pinMode(SDA_PIN,INPUT);
pinMode(SCL_PIN, OUTPUT);
digitalWrite(SCL_PIN, HIGH);
//Start MySensors and send the Sketch Version Information to the Gateway
node.begin();
node.sendSketchInfo(SKETCH_NAME, SKETCH_VERSION);
//Register all sensors
node.present(CHILD_ID_DIGICODE, S_CUSTOM);
node.present(KEYPAD_ID_SCENE, S_SCENE_CONTROLLER);
node.present(CHILD_ID_VOLTAGE, S_MULTIMETER);
//Load last Scenestates from EEPROM (7 scenestates available)
for (int i = 0 ; i < MAX_SCENE; i++)
{
keyState[i] = node.loadState(i);
#ifdef DEBUG
Serial.print(" "); Serial.print(keyState[i]);
#endif
}
//Setup done !
blinkLedFastly(3);
//Print setup debug
#ifdef DEBUG
int duration = millis() - startTime;
Serial.println("");
Serial.print("[Setup duration: "); Serial.print(duration, DEC); Serial.println(" ms]");
#endif
}
/**************************************************************************************/
/* Main loop */
/**************************************************************************************/
void loop()
{
//Sleep, node wakes up on key interrupt
byte interuptionType = node.sleep(SDA_PIN - 2, FALLING);
//Verify if a key was pressed
if (interuptionType == 0)
{
return;
}
//Get time (for a complete loop)
#ifdef DEBUG
unsigned long startTime = millis();
#endif
//Get first digit
byte key = getKeyPressed();
tone(BUZZER_PIN, BUZZ_FREQ_KEY, BUZZ_TIME_KEY);
//Check validity
if (key == 0)
{
Serial.print("bah si !");
Serial.println(interuptionType);
blinkLedFastlyAndBuzz(3);
return;
}
//Inform user that key is valid
blinkLedFastly(1);
int digicode = key * 1000;
//Check if key corresponds to a scene touch or a code
if (key > 9)
{
//Update scene state
node.saveState(key - 10, (boolean)node.loadState(key - 10)?false:true);
//Report data to the gateway
long voltage = getVoltage();
node.send(node.loadState(key - 10)?msgSceneOn.set(key - 10):msgSceneOff.set(key - 10));
node.send(msgVolt.set(voltage / 1000.0, 3));
int batteryPcnt = round((voltage - BATTERY_ZERO) * 100.0 / (BATTERY_FULL - BATTERY_ZERO));
if (batteryPcnt > 100) {batteryPcnt = 100;}
node.sendBatteryLevel(batteryPcnt);
//Print debug
#ifdef DEBUG
Serial.print("Scene ");
Serial.print(key - 10);
Serial.print(": ");
Serial.print((boolean)node.loadState(key - 10)?" 1 ":" 0 ");
Serial.print(" ");
Serial.print(voltage / 1000.0);
Serial.print(" v");
int duration = millis() - startTime;
Serial.print(" ");
Serial.print("["); Serial.print(duration, DEC); Serial.println(" ms]");
Serial.flush();
#endif
}
else
{
//Wait for next key pressed or WAITING_TIME without action
interuptionType = node.sleep(SDA_PIN - 2, FALLING, WAITING_TIME);
//Verify if a key was pressed
if (interuptionType == 0)
{
blinkLedFastlyAndBuzz(3);
return;
}
//Get second digit
key = getKeyPressed();
tone(BUZZER_PIN, BUZZ_FREQ_KEY, BUZZ_TIME_KEY);
//Check validity
if (key == 0 || key > 9)
{
blinkLedFastlyAndBuzz(3);
node.sleep(1000);
return;
}
//Inform user that key is valid
blinkLedFastly(1);
digicode = digicode + key * 100;
//Wait for next key pressed or WAITING_TIME without action
interuptionType = node.sleep(SDA_PIN - 2, FALLING, WAITING_TIME);
//Verify if a key was pressed
if (interuptionType == 0)
{
blinkLedFastlyAndBuzz(3);
return;
}
//Get third digit
key = getKeyPressed();
tone(BUZZER_PIN, BUZZ_FREQ_KEY, BUZZ_TIME_KEY);
//Check validity
if (key == 0 || key > 9)
{
blinkLedFastlyAndBuzz(3);
node.sleep(1000);
return;
}
//Inform user that key is valid
blinkLedFastly(1);
digicode = digicode + key * 10;
//Wait for next key pressed or WAITING_TIME without action
interuptionType = node.sleep(SDA_PIN - 2, FALLING, WAITING_TIME);
//Verify if a key was pressed
if (interuptionType == 0)
{
blinkLedFastlyAndBuzz(3);
return;
}
//Get fourth digit
key = getKeyPressed();
tone(BUZZER_PIN, BUZZ_FREQ_KEY, BUZZ_TIME_KEY);
//Check validity
if (key == 0 || key > 9)
{
blinkLedFastlyAndBuzz(3);
node.sleep(1000);
return;
}
//Inform user that key is valid
blinkLedFastly(1);
digicode = digicode + key;
//Report data to the gateway
long voltage = getVoltage();
node.send(msgCode.set(digicode));
node.send(msgVolt.set(voltage / 1000.0, 3));
int batteryPcnt = round((voltage - BATTERY_ZERO) * 100.0 / (BATTERY_FULL - BATTERY_ZERO));
if (batteryPcnt > 100) {batteryPcnt = 100;}
node.sendBatteryLevel(batteryPcnt);
//Print debug
#ifdef DEBUG
Serial.print("Complete code: ");
Serial.print(digicode);
Serial.print(" ");
Serial.print(voltage / 1000.0);
Serial.print(" v");
int duration = millis() - startTime;
Serial.print(" ");
Serial.print("["); Serial.print(duration, DEC); Serial.println(" ms]");
Serial.flush();
#endif
//Play final song instead of sleeping
playFinalSong();
}
//Wait to avoid false interruption
node.sleep(1000);
}
/**************************************************************************************/
/* Allows to play the final song. */
/**************************************************************************************/
void playFinalSong()
{
//Declare local variables
int i, duration;
// step through the song arrays
for (i = 0; i < songLength; i++)
{
// length of note/rest in ms
duration = beats[i] * tempo;
// is this a rest?
if (notes[i] == ' ')
{
delay(duration); // then pause for a moment
}
else // otherwise, play the note
{
tone(BUZZER_PIN, frequency(notes[i]), duration);
delay(duration); // wait for tone to finish
}
delay(tempo/10); // brief pause between notes
}
}
/**************************************************************************************/
/* takes a note character (a-g), and returns the corresponding frequency in Hz */
/* for the tone() function. */
/**************************************************************************************/
int frequency(char note)
{
//Declare local variables
int i;
const int numNotes = 8; // number of notes we're storing
// The following arrays hold the note characters and their
// corresponding frequencies. The last "C" note is uppercase
// to separate it from the first lowercase "c". If you want to
// add more notes, you'll need to use unique characters.
// For the "char" (character) type, we put single characters
// in single quotes.
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int frequencies[] = {262, 294, 330, 349, 392, 440, 494, 523};
// Now we'll search through the letters in the array, and if
// we find it, we'll return the frequency for that note.
for (i = 0; i < numNotes; i++) // Step through the notes
{
if (names[i] == note) // Is this the one?
{
return(frequencies[i]); // Yes! Return the frequency
}
}
return(0); // We looked through everything and didn't find it,
// but we still need to return a value, so return 0.
}
/**************************************************************************************/
/* Allows to get the pressed key. */
/**************************************************************************************/
byte getKeyPressed()
{
//Get first bit
digitalWrite(SCL_PIN, LOW);
delayMicroseconds(100);
digitalWrite(SCL_PIN, HIGH);
//Read all keys
for(int i = 0; i < KEYBOARD_SIZE; i++)
{
keyState[i] = (digitalRead(SDA_PIN) == LOW);
digitalWrite(SCL_PIN, LOW);
delayMicroseconds(100);
digitalWrite(SCL_PIN, HIGH);
delayMicroseconds(100);
}
//Read keyboard table to find the pressed key
byte keyPressed = -1;
for(int i = 0 ; i < KEYBOARD_SIZE; i++)
{
if (keyState[i])
{
keyPressed = i;
}
}
//Return the result
return (keyPressed + 1);
}
/**************************************************************************************/
/* Allows to fastly blink the LED. */
/**************************************************************************************/
void blinkLedFastly(byte loop)
{
byte delayOn = 150;
byte delayOff = 150;
for (int i = 0; i < loop; i++)
{
blinkLed(LED_PIN, delayOn);
delay(delayOff);
}
}
/**************************************************************************************/
/* Allows to fastly blink the LED and to play a sound on the buzzer. */
/**************************************************************************************/
void blinkLedFastlyAndBuzz(byte loop)
{
byte delayOn = 150;
byte delayOff = 150;
for (int i = 0; i < loop; i++)
{
blinkLed(LED_PIN, delayOn);
tone(BUZZER_PIN, BUZZ_FREQ_ERROR, delayOff);
delay(delayOff);
}
}
/**************************************************************************************/
/* Allows to blink a LED. */
/**************************************************************************************/
void blinkLed(byte pinToBlink, int delayInMs)
{
digitalWrite(pinToBlink,HIGH);
delay(delayInMs);
digitalWrite(pinToBlink,LOW);
}
/**************************************************************************************/
/* Allows to get the real Vcc (return value in mV). */
/* http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ */
/**************************************************************************************/
long getVoltage()
{
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
delay(50); // Let mux settle a little to get a more stable A/D conversion
//Start a conversion
ADCSRA |= _BV( ADSC );
//Wait for it to complete
while (bit_is_set(ADCSRA, ADSC));
//Compute and return the value
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both
long result = (high << 8) | low;
result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
return result; // Vcc in millivolts
}
David.