302 lines
11 KiB
C++
302 lines
11 KiB
C++
/*
|
|
The Sensor Net Arduino library adds a new layer on top of the RF24 library.
|
|
It handles radio network routing, relaying and ids.
|
|
|
|
Created by Henrik Ekblad <henrik.ekblad@gmail.com>
|
|
|
|
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.
|
|
*/
|
|
|
|
#ifndef Sensor_h
|
|
#define Sensor_h
|
|
|
|
#include "Config.h"
|
|
#include <nRF24L01.h>
|
|
#include <RF24.h>
|
|
#include <RF24_config.h>
|
|
#include <Arduino.h>
|
|
#include <stddef.h>
|
|
#include <SPI.h>
|
|
#include <EEPROM.h>
|
|
#include <avr/pgmspace.h>
|
|
#include <stdarg.h>
|
|
|
|
#ifdef DEBUG
|
|
#define debug(x,...) debugPrint(x, ##__VA_ARGS__)
|
|
#else
|
|
#define debug(x,...)
|
|
#endif
|
|
|
|
#define LIBRARY_VERSION "1.2+"
|
|
#define PROTOCOL_VERSION 1
|
|
#define BAUD_RATE 115200
|
|
|
|
#define AUTO 0xFF // 0-254. Id 255 is reserved for auto initialization of radioId.
|
|
#define NODE_CHILD_ID 0xFF // Node child id is always created for when a new sensor is detected
|
|
#define EEPROM_RADIO_ID_ADDRESS 0 // Where to store radio id in EEPROM
|
|
#define EEPROM_RELAY_ID_ADDRESS 1 // Where to store relay id in EEPROM
|
|
#define EEPROM_DISTANCE_ADDRESS 2 // Where to store distance to gateway in EEPROM
|
|
|
|
// This is the radioId for sensor net gateway receiver sketch (where all sensors should send their data).
|
|
// This is also act as base value for sensor radioId
|
|
#define BASE_RADIO_ID ((uint64_t)0xABCDABC000LL)
|
|
#define GATEWAY_ADDRESS ((uint8_t)0)
|
|
#define BROADCAST_ADDRESS ((uint8_t)0xFF)
|
|
#define TO_ADDR(x) (BASE_RADIO_ID + x)
|
|
|
|
#define WRITE_PIPE ((uint8_t)0)
|
|
#define CURRENT_NODE_PIPE ((uint8_t)1)
|
|
#define BROADCAST_PIPE ((uint8_t)2)
|
|
|
|
#define ACK_MAX_WAIT 50
|
|
#define ACK_SEND_DELAY 10
|
|
|
|
#define WRITE_RETRY 5
|
|
#define FIND_RELAY_RETRIES 20
|
|
|
|
|
|
#define MAX_MESSAGE_LENGTH 32
|
|
|
|
// Message types
|
|
typedef enum {
|
|
M_PRESENTATION = 0,
|
|
M_SET_VARIABLE = 1,
|
|
M_REQ_VARIABLE = 2,
|
|
M_ACK_VARIABLE = 3,
|
|
M_INTERNAL = 4
|
|
} messageType;
|
|
|
|
// Sensor variables that can be used in sketches
|
|
typedef enum {
|
|
V_TEMP,V_HUM, V_LIGHT, V_DIMMER, V_PRESSURE, V_FORECAST, V_RAIN,
|
|
V_RAINRATE, V_WIND, V_GUST, V_DIRECTION, V_UV, V_WEIGHT, V_DISTANCE,
|
|
V_IMPEDANCE, V_ARMED, V_TRIPPED, V_WATT, V_KWH, V_SCENE_ON, V_SCENE_OFF,
|
|
V_HEATER, V_HEATER_SW, V_LIGHT_LEVEL, V_VAR1, V_VAR2, V_VAR3, V_VAR4, V_VAR5,
|
|
V_UP, V_DOWN, V_STOP, V_IR_SEND, V_IR_RECEIVE, V_FLOW, V_VOLUME, V_LOCK_STATUS
|
|
} variableType;
|
|
|
|
// Internal messages
|
|
typedef enum {
|
|
I_BATTERY_LEVEL, I_BATTERY_DATE, I_LAST_TRIP, I_TIME, I_VERSION, I_REQUEST_ID,
|
|
I_INCLUSION_MODE, I_RELAY_NODE, I_LAST_UPDATE, I_PING, I_PING_ACK,
|
|
I_LOG_MESSAGE, I_CHILDREN, I_UNIT, I_SKETCH_NAME, I_SKETCH_VERSION
|
|
} internalMessageType;
|
|
|
|
// Sensor types
|
|
typedef enum {
|
|
S_DOOR, S_MOTION, S_SMOKE, S_LIGHT, S_DIMMER, S_COVER, S_TEMP, S_HUM, S_BARO, S_WIND,
|
|
S_RAIN, S_UV, S_WEIGHT, S_POWER, S_HEATER, S_DISTANCE, S_LIGHT_LEVEL, S_ARDUINO_NODE,
|
|
S_ARDUINO_RELAY, S_LOCK, S_IR, S_WATER
|
|
} sensor;
|
|
|
|
// Possible return values by validate() when doing crc check of received message.
|
|
enum {
|
|
VALIDATE_OK, VALIDATE_BAD_CRC, VALIDATE_BAD_VERSION
|
|
};
|
|
|
|
// The message structure
|
|
typedef struct {
|
|
uint8_t crc : 8; // 8 bits crc
|
|
uint8_t version : 3; // 3 bits protocol version
|
|
uint8_t binary : 1; // 1 bit. Data is binary and should be encoded when sent to sensor net gateway
|
|
uint8_t from : 8; // 8 bits. RadioId of sender node
|
|
uint8_t to : 8; // 8 bits. RadioId of destination node
|
|
uint8_t last : 8; // 8 bits. RadioId of last node this message passed
|
|
uint8_t childId : 8; // 1 byte. Up to MAX_CHILD_DEVICES child sensors per radioId
|
|
uint8_t messageType : 4; // 4 bits. Type of message. See messageType
|
|
|
|
uint8_t type : 8; // 8 bits. variableType or deviceType depending on messageType
|
|
} header_s;
|
|
|
|
typedef struct {
|
|
header_s header;
|
|
char data[MAX_MESSAGE_LENGTH - sizeof(header_s) + 1]; // Each message can transfer a payload. Add one extra byte for \0
|
|
} message_s;
|
|
|
|
|
|
class Sensor : public RF24
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor
|
|
*
|
|
* Creates a new instance of Sensor class.
|
|
*
|
|
* @param _cepin The pin attached to RF24 Chip Enable on the RF module (defualt 9)
|
|
* @param _cspin The pin attached to RF24 Chip Select (default 10)
|
|
*/
|
|
Sensor(uint8_t _cepin=9, uint8_t _cspin=10);
|
|
|
|
/**
|
|
* Begin operation of the MySensors library
|
|
*
|
|
* Call this in setup(), before calling any other sensor net library methods.
|
|
* @param radioId The unique id (1-254) for this sensor. Default 255 (auto mode).
|
|
* @param paLevel Radio PA Level for this sensor. Default RF24_PA_MAX
|
|
* @param channel Radio channel. Default is channel 76
|
|
* @param dataRate Radio transmission speed. Default RF24_2MBPS
|
|
*/
|
|
void begin(uint8_t radioId=AUTO, rf24_pa_dbm_e paLevel=RF24_PA_LEVEL, uint8_t channel=RF24_CHANNEL, rf24_datarate_e dataRate=RF24_DATARATE);
|
|
|
|
uint8_t getRadioId();
|
|
|
|
/**
|
|
* The arduino node must send a presentation of all the sensors connected before any
|
|
* variable changes will be registered on sensor net gateway side.
|
|
* Usually it's good to present all sensors when arduino starts up (setup).
|
|
* Note that gateway must be in include mode to register new devices.
|
|
*
|
|
* @param childId The unique child id for the different sensors connected to this arduino. 0-254.
|
|
* @param sensorType Sensor types to create. They will be numbered from 0 up to 127.
|
|
*/
|
|
void sendSensorPresentation(uint8_t childId, uint8_t sensorType);
|
|
|
|
|
|
/**
|
|
* Sends a variable change to sensor net gateway (or another sensor if radioId is specified)
|
|
*
|
|
* @param radioId The radioId of other node in radio network (used for communicating between sensors)
|
|
* @param childId The child id for which to update variable. Value can be 0-254.
|
|
* @param variableType The variableType to update
|
|
* @param value New value of the variable
|
|
*/
|
|
|
|
void sendVariable(uint8_t childId, uint8_t variableType, const char *value);
|
|
void sendVariable(uint8_t childId, uint8_t variableType, double value, int decimals);
|
|
void sendVariable(uint8_t childId, uint8_t variableType, unsigned long value);
|
|
void sendVariable(uint8_t childId, uint8_t variableType, long value);
|
|
void sendVariable(uint8_t childId, uint8_t variableType, unsigned int value);
|
|
void sendVariable(uint8_t childId, uint8_t variableType, int value);
|
|
|
|
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, const char *value);
|
|
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, double value, int decimals);
|
|
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, unsigned long value);
|
|
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, long value);
|
|
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, unsigned int value);
|
|
void sendVariable(uint8_t radioId, uint8_t childId, uint8_t variableType, int value);
|
|
|
|
/**
|
|
* Sends sketch info to sensor net gateway for this radio node.
|
|
* @param name String containing a short Sketch name
|
|
* @param version String containing a short Sketch version
|
|
*/
|
|
void sendSketchInfo(const char *name, const char *version);
|
|
|
|
/**
|
|
* Sends sketch name to sensor net gateway for this radio node.
|
|
* @param info String containing a short Sketch name and version
|
|
*/
|
|
void sendSketchName(const char *name);
|
|
|
|
/**
|
|
* Sends sketch version to sensor net gateway for this radio node.
|
|
* @param info String containing a short Sketch name and version
|
|
*/
|
|
void sendSketchVersion(const char *version);
|
|
|
|
/**
|
|
* Sends battery status to sensor net gateway for this radio node.
|
|
* @param value Set a value between 0-100(%)
|
|
*/
|
|
void sendBatteryLevel(int value);
|
|
|
|
/**
|
|
* Requests a variable value from sensor net gateway (or another sensor). This method will not wait for an answer.
|
|
* You should use mesageAvailable/getMessage to pick up the response.
|
|
*
|
|
* @param radioId The radioId of other node in radio network (used when fetching from other node)
|
|
* @param childId The unique child id for the different sensors connected to this arduino. 0-254.
|
|
* @param variableType The variableType to fetch
|
|
*/
|
|
void requestStatus(uint8_t childId, uint8_t variableType);
|
|
void requestStatus(uint8_t radioId, int8_t childId, uint8_t variableType);
|
|
|
|
/**
|
|
* Requests status for a sensor variable from sensor net gateway. Waits until message arrives.
|
|
*
|
|
* @param radioId The radioId of other node in radio network (used when fetching from other node)
|
|
* @param childId The unique child id for the different sensors connected to this arduino. 0-254.
|
|
* @param variableType The variableType to fetch
|
|
* @return The variable value
|
|
*/
|
|
char *getStatus(uint8_t childId, uint8_t variableType);
|
|
char *getStatus(uint8_t radioId, int8_t childId, uint8_t variableType);
|
|
|
|
|
|
/**
|
|
* Fetches time from sensor net gateway
|
|
*/
|
|
void requestTime();
|
|
unsigned long getTime();
|
|
|
|
/**
|
|
* Fetches unit setting from sensor net gateway. Returns true if metric system has been selected which means
|
|
* that sensor should report it's information in: celsius, meter, cm, gram, km/h, m/s etc..
|
|
* If false is returned the sensor should report data in imperial system which means
|
|
* fahrenheit, feet, gallon, mph etc...
|
|
*/
|
|
void requestIsMetricSystem();
|
|
bool isMetricSystem();
|
|
|
|
|
|
/**
|
|
* Busy waits until there is a message for this node available to be read
|
|
*/
|
|
message_s waitForMessage(void);
|
|
|
|
/**
|
|
* Returns true if there is a message addressed for this node is available to be read
|
|
*/
|
|
boolean messageAvailable(void);
|
|
|
|
/**
|
|
* Returns the last received message
|
|
*/
|
|
message_s getMessage(void);
|
|
|
|
/**
|
|
* Validates consistency of the message including CRC and protocol version
|
|
*/
|
|
uint8_t validate(uint8_t length);
|
|
|
|
|
|
#ifdef DEBUG
|
|
void debugPrint(const char *fmt, ... );
|
|
int freeRam();
|
|
#endif
|
|
|
|
|
|
protected:
|
|
uint8_t failedTransmissions;
|
|
boolean isRelay;
|
|
uint8_t radioId;
|
|
uint8_t distance; // This nodes distance to sensor net gateway (number of hops)
|
|
uint8_t relayId;
|
|
message_s msg; // Buffer for incoming messages.
|
|
char convBuffer[20];
|
|
|
|
void setupRadio(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataRate);
|
|
void findRelay();
|
|
boolean send(message_s message, int length);
|
|
boolean sendWrite(uint8_t dest, message_s message, int length);
|
|
boolean readMessage();
|
|
void buildMsg(uint8_t from, uint8_t to, uint8_t childId, uint8_t messageType, uint8_t type, const char *data, uint8_t length, boolean binary);
|
|
void sendInternal(uint8_t variableType, const char *value);
|
|
boolean sendVariableAck();
|
|
boolean sendData(uint8_t from, uint8_t to, uint8_t childId, uint8_t messageType, uint8_t type, const char *data, uint8_t length, boolean binaryMessage);
|
|
|
|
|
|
|
|
private:
|
|
message_s ack; // Buffer for ack messages.
|
|
|
|
void initializeRadioId();
|
|
uint8_t crc8Message(message_s, uint8_t length);
|
|
char* get(uint8_t nodeId, uint8_t childId, uint8_t sendType, uint8_t receiveType, uint8_t variableType);
|
|
char *getInternal(uint8_t variableType);
|
|
};
|
|
|
|
#endif
|