Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 3 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
|
A full home automation Arduino project with voice control - without wires. I designed, built and programmed it in my style, following only my own fantasy. Every each parts are handmade.
IntrodutionThe system controls the heater gas boiler, the lights in the flat, the airing fan and my media player.
There are two autonomous Arduino-based units communicating on a synchronized Bluetooth link - connecting and synchronizing each other automatically, so there is no outdated or missing information on the screens.
The Central Unit accepts commands, and switches the proper local appliance or forwards the command to the Thermostat Unit to perform.
The whole system can be locked with RFID card – I designed a fully functional RFID card handler for it.
And yes, the Central Unit talks! Says a greeting message when I connect, what’s more it laughs at me if I try to unblock it with an unlisted RFID card for instance.
VideoJust a click, and you will see and understand everything!
Central UnitDeveloped on Arduino / Genuino 2560 board, HC-05 Bluetooth adapters, RF 315/433MHz receiver, IR receiver, MFRC-522 RFID reader and programmer, Elechouse VR3 module, TM1637 display drivers, ST9720 (12864) lcd screen, 4x4 matrix keypad, DS3231 RTC chip, 4ch relay board, ISD1820PY voice chips with LM386 amplifier, active and NE555 controlled buzzers.
The Central Unit accepts Voice, Bluetooth, IR and RF remote and Matrix keypad commands - in order to control the local devices, or forwards the command to the Thermostat unit, and receives working state reports from it - via Synchronized Bluetooth link.
This unit sends working reports via Bluetooth to an Android device, screen prints, and audible reports (Speech and buzzers).
All system settings and information are stored in the EEPROM (RFID cards, locked/unlocked state, device states, alarm clock etc.) .
Thermostat UnitDeveloped on Arduino Nano (or higher) board, DS18B20 temperature sensor,
HC-05 Bluetooth adapter, I2C 128X64 bicolor OLED display.
It handles the Heater gas boiler, the bathroom Airing ventilator and the Kitchen lights - switched with relays. Accepts commands from the Central Unit, and sends reports back.
The intelligent Thermostat Routine controls the heater,
with open window-sensing and error detection.
Works in Celsius and Fahrenheit unit (by changing it converts the stored previous temperature values), and calculates natural gas cost with statistics.
This unit is as an advanced version of my earlier published standalone Bluetooth thermostat project.
RFID Security and System Lock[check video at 10:10]
The Central unit contains a complete RFID handler function I designed with Card Manager menu („#” button from the main screen) allows to delete and store new tags in the EPPROM memory. If we delete a tag, the auto-sort procedure will follow to keep avoid empty rows in the list.
If we lock the system, all appliances will be turned off, all commands will be ignored - only the thermostat routine will keep the temperature has been set earlier.
Two important features:
- After a power outage the system stays in locked status.
- If only one device (Central or Thermostat unit) is locked, and the another is not (for example one is turned off), after the next synch procedure they lock down each other instantly - the locked status, so the security has always the highest priority.
[check video at 14:15]
Two fully autonomous units has to work together – can be power ON and OFF anytime! If one of these will be switched off suddenly, there is no chance to tell it the another one - would show outdated temperature value and device states - or will miss system events if I power it on later!
So I created the model as I call "Cyclic Binary Synchronous Sequences". My solution can be seen below.
There are function buttons on both unit as well as the Central Unit accepts commands from Android device, Voice commands, IR and RF remote signals.
Using the RF remote;
"A" - Airing, "B" - Kitchen lights, "C" - Media player, "D" - Desk lights
We have IR remote
with direct-device and numeric buttons:
All attached home appliances can be controlled directly, but the system also accepts numeric codes (from matrix keypad, IR remote or Android smartphone); 10..24 or 50..76 are the target temperature values, and there are service codes and control codes.
We can also send acronym messages from smartphone with numeric parameters, like adjust the real time clock; "t1234" - that means 12:34.
I programmed a structure handles the Elechouse VR3 module with groups, using this even the typical target temperatures can adjust with voice commands.
The heater function has two working ways:
- One Time Heating. 15 minutes timed mode, useful at spring or autumn evenings
- Thermostat mode (higher priority). The adjusted target temperature stored in EEPROM. The program detects hardware errors and window opening - in these cases the heater stops and/or will not start.
After a heating period the Thermostat Unit creates a summary contains the elapsed time in minutes, the temperature difference and the natural gas cost - and sends to the Central Unit via the Bluetooth link. Counts the heating minutes, which is stored in the EEPROM memory, and can be reset manually.
A voice command "System - Cost" or "System - Cost Zero" also handles the calculated cost value.
The cost value is the multiplication of the minutes and the Cost Coefficient.
I determined the U.S. average annual natural gas residential price;
$10.52 / 1000ft^3 (www.eia.gov), 1000ft^3 = 28.31685m^3, and my boiler uses up 1m^3 natural gas in 50 minutes, so the Cost Coefficient equals „(10.52 / 28.31685) / 50”.
-127 or -196.60 are HW errors, +85 is typical SW error, but can be fire, or a broken window. A false measured temperature would cause running the gas heater continuously, so in this case all attached home appliances will turned off by the system.
Intelligent Thermostat RoutineFrequent, short-term switching of the heater gas boiler would cut short its lifetime, that's why the system calculates with correction variables. Lower temperature demands greater correction variable, because the walls are colder and adsorb better the warmth from the freshly heated-up air, so the above described effect would more stronger.
Changing Measurement UnitThere are two ways for it:
- Set the target temperature using Android phone, IR remote or Matrix keypad:
[10] ... [24] numbers will be accepted as Celsius, or
[50] ... [76] numbers as Fahrenheit
The given number will declare the unit of the measurement. - Flip measurement unit by pressing the INCR and DECR buttons at the same time. In this case the current target temperature will be converted.
By changing measurement unit, the system converts the previously stored temperature values used for statistics and trend analysis - even during a heating period.
Open Window DetectionIf in a measurement cycle the temperature drops (-0.2C/ -0.36F), it will evaluate as a window is open, the heater stops or will not start, and the airing fan will turn on to help refresh the air.
If the temperature stops falling, the air becomes warmer (+0.12C/ +0.216F) due to the heat capacity of the environment, the system will switch back to normal mode.
Android Help MenuPlenty of commands, hard to keep in mind. Just type „HELP” on your Android phone, and you will get a detailed user’s guide!
After connecting, the user has to send „hi” first, as "Two-factor authentication" - with the Bluetooth PIN code. Otherwise the user will not receive any information and unable to send commands.
If the user sends anything else instead of 'hi', will be disconnected immediately.
If we send „bye”, the system will also disconnect us, but a voice command „System - Disconnect” will do the same.
I have built a DS3231 RTC chip into the Central Unit, and I coded a routine accepts current and alarm times from a smartphone.
The alarm procedure takes 10 minutes, uses a very loud active buzzer and flashes the desk lights – can be stop by saying „Silence!”, pushing a key or sending a Bluetooth command „aloff”.
The alarm time also stored in the EEPROM memory.
If the user's first message is not 'hi', at the next loop-cycle the Intrusion Avoidance Algorithm takes control and attacks the connected Bluetooth device. My showcase publication shows how it works.
// ---- CENTRAL UNIT - Smart Home
// Program code of an intelligent Arduino smarthome system - Central Unit.
// Based on Arduino / Genuino 2560 board, HC-05 Bluetooth adapters, RF 315/433MHz receiver, IR receiver, MFRC-522 reader and programmer,
// Elechouse VR3 module, TM1637 display drivers, ST9720 (12864) lcd screen, 4x4 matrix keypad, DS3231 RTC chip, 4ch relay board,
// ISD1820PY voice chips with LM386 amplifier, active and NE555 controlled buzzers.
//
// It controls the desk lights and media player (as local devices), and controls the another unit of the system,
// the Thermostat Unit via Bluetooth. These units connect and synch each oder automatically - so there is no missing or outdated information in the system.
//
// The Central Unit accepts Bluetooth (Android for instance), Voice (speech), IR and RF remote, and Keypad commands in order to control
// the local devices, or forwards the command to the Thermostat unit, and receives working state reports from it.
// The whole system can be locked by RFID cards (with a full-function card handler menu).
// All system settings and informations (RFID cards, locked/unlocked state, device states, alarm clock, etc.) are stored in EEPROM.
//
// The another part of the system is the Thermostat Unit, based on Arduino Nano, DS18B20 thermo sensor, HC-05 Bluetooth, I2C 128X64 OLED display.
// Controls the HEATER gas boiler, the bathroom AIRING ventilator and the kitchen LIGHTING. The program detects hardware errors and window
// opening - in these cases the heater stops and/or will not start.
// Works in Celsius and Fahrenheit unit (by changing it converts the stored previous temperature values), and calculates natural gas cost.
// ------------------------------------------------------------------------------------------------------------------------------------
//
// Designed, built and programmed
// by Gyula Osi.
// All rights reserved.
// ------------------------------------------------------------------------------------------------------------------------------------
// ---- MFRC-522 & System Security
#include <SPI.h>
#include <MFRC522.h>
#define SS_PIN 53 // RST: 48, MISO: 50, MOSI: 51, SCK: 52, SDA: 53
#define RST_PIN 48
MFRC522 rfid(SS_PIN, RST_PIN); // instance of the class
MFRC522::MIFARE_Key key;
String strC; // collect and store readings
#define arrNUIDSize 4
String strNUID[arrNUIDSize];
char arrNUID[arrNUIDSize][20]; // number of strings & length of each strings
#define lckItems 2
// i --> 0 1
const int lock_strings[lckItems] = {98, 97};
bool locked; // state of syslock
bool cardManager = 0;
// i --> 0 1 2 3 4 5 6 7
bool cardBoolSwitches[8] = {1, 1, 0, 0, 0, 0, 0, 0};
// ---- Array of Binary Card Operators & Process State Codes
// [i] FUNCT
// 0 has been seen (temp=1)
// 1 get NUID (call at startup)
// 2 not stored yet
// 3 delete
// 4 already stored
// 5 new NUID
// 6 invalid type of card
// 7 memory full
// i --> 0 1 2 3
bool delNUID[arrNUIDSize] = {0, 0, 0, 0}; // marked for delete
// ---- Receive IR
#include <IRremote.h>
const int RECV_PIN = 8;
IRrecv irrecv(RECV_PIN);
decode_results results;
// ---- Matrix Hexakeys and Buttons
#include <Keypad.h>
const byte matrixR = 4; // R
const byte matrixC = 4; // C
char matrixHEXkeys[matrixR][matrixC] = { //define the cymbols on the buttons of the keypads
// iR/C --> R0C0 R0C1 R0C2 R0C3 R1C0 R1C1 R1C2 R1C3 R2C0 R2C1 R2C2 R2C3 R3C0 R3C1 R3C2 R3C3
{'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', 'C'}, {'*', '0', '#', 'D'}
};
byte pinsMatrixR[matrixR] = {40, 42, 44, 46}; //connect to the row pinouts of the keypad
byte pinsMatrixC[matrixC] = {43, 45, 47, 49}; //connect to the column pinouts of the keypad
Keypad customKeypad = Keypad(makeKeymap(matrixHEXkeys), pinsMatrixR, pinsMatrixC, matrixR, matrixC); //initialize an instance of class NewKeypad
int matrixVal; // stores analog value when button is pressed
int sum = 0; // to collect Control Codes from Keypad and IR
char sumChar[2]; // to conv in into char for writeout
const byte btnAl = 28;
// ---- RF 315/330/433MHz recv
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
const byte pwrRF = 27;
bool rfOn;
// ---- Display TM1637
#include "SevenSegmentTM1637.h"
#include "SevenSegmentExtended.h"
const byte CLK0 = 4;
const byte DIO0 = 5;
SevenSegmentExtended d0(CLK0, DIO0);
const byte CLK1 = 6;
const byte DIO1 = 7;
SevenSegmentExtended d1(CLK1, DIO1);
char sevenTempr[4];
int sumPrev;
// ---- Display ST7920
#include "U8glib.h"
U8GLIB_ST7920_128X64 u8g(39, 38, 41, U8G_PIN_NONE); // screen constructor13, 12, 9, U8G_PIN_NONE
byte frame = 0;
bool prntRTC = 0;
// ---- Internal Serial Communication & State of Remote Appliances
bool onlink = 1; // 1 in order to send a sync request for binary reports, and try to toggle the Thermostat unit into
// onlink mode at startup. After an unsuccesful attempt this bool will turn zero within five seconds.
const int requestInt = 99; // request for cyclic binary reports
String recvdStates; // store the received report
bool gotReport = 0; // the Thermostat unit has been seen since startup of the Central unit
const char expiredReport = 'X'; // the expired report is empty, contains only the preamble
String strTemprRecvd; // store the tempr value extracted from the data stream sent by the Thermostat unit
// ---- Memory Management
#include <EEPROM.h> // memory calls
// i --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13
const byte addr[14] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 22};
// -------- Memory Map --------
//
// [i] VAL
// 0 bool locked
// 1 bool REMOVED FEATURE
// 2 bool prntRTC
// 3 bool relayDLState
// 4 bool relayMPState
// ----> byte al[i] VAL
// 5 byte al[4] 0 alH0
// 6 byte al[4] 1 alH1
// 7 byte al[4] 2 alM0
// 8 byte al[4] 3 alM1
// ----
// 9 bool alOn
// 10 bool rfOn
// 11 bool vrOn
// 12 byte RFID INIT
// 13 byte RFID REL
//
// ------------------------------
byte pointer = 0;
// ---- External Serial Communication
#define exRXSize 5
char exRX[exRXSize]; // variable to receive data from the serial port
bool auth = 0;
const byte ledAuth = 26;
bool startup = 1; // otherwise the self defense routine would run at startup
const byte extBTen = 3; // ext bt enable
// ---- Local Appliances
const byte relayDL = 9; // desk lights
bool relayDLState;
const byte relayMP = 12; // media player
bool relayMPState;
// ---- Strings and Related Features
char inCharFromIntBT;
String strCollectFromIntBT;
#define strSize 6
String str[strSize];
#define functItems 74
// i --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
const String functStr[functItems] = { "READY.", "Voice command", "Bluetooth command", "IR code received", "BT code rejected", "RF signal received", "Key pressed", "Mediaplayer is ", "Desklights is ", "CODE= ", "* DEL | ENTER #", "Central unit ", "un", "locked!", "Desklights is on.", "Desklights is off.", "Mediaplayer is on.", "Mediaplayer is off.", "Temperature= ", ".", "!", "Thermostat Offlink!", "Thermostat Onlink!", "ONLINK", "CARD MANAGER", "del: ", "A", "B", "C", "D", "Card Deleted!", "Already Stored!", "New Card Stored!", "Memory Full!", "Invalid type of Card!", "Card Rejected!", "Card Accepted!", "Authorized User!", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "SYSTEM REBOOT SOON", "You may connect now.", "Good bye.", "ERROR", "Clock adjusted.", "Please say", "What temperature", "would you like?", "a system ", "function!", "User disconnected.", "Alarm accepted. ", "Alarm rejected.", "Alarm disabled.", "Alarm enabled. ", ":", "Wake up!", "RF receiver on.", "RF receiver off.", "Target temperature:", "[10]-[24] Celsius", "[50]-[76] Fahrenheit", "VR3 enabled.", "VR3 disabled.", "The system is locked!", "Sending guide...", "No connected user.", "Guide sent." };
#define sevenItems 18
// i --> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
const String sevenStr[sevenItems] = {" ", "SYS_", "boot", "CArd", "MENU", " dEL", " Add", "A_St", "FULL", "CodE", "----", "LEtS", "PLAY", "Good", " bYE", "Conn", "SCAN", "AL " };
// ---- System Timers
#include <elapsedMillis.h>
// ---- Countdn tmr for synch request or devalidation of received report
elapsedMillis timer0; // 8-bit, PWM timer, used by function elapsedMillis()
#define sysTmrExpired 5000 // timer of cyclic binary report expiration [ms]
// ---- Cyclic timers for various system functions as below;
#define cycTmrInterval0 200 // used for RTC call
#define cycTmrInterval1 800 // icon blink tmr
#define cycTmrInterval2 2400 // seven segment timed printouts
#define cycTmrInterval3 5000 // NUID event display
#define cycTmrDim 4
bool cTmrUp[cycTmrDim]; // binary state of each tmrs
unsigned long cTmrPrev[cycTmrDim]; // prev vals for comparison
// ---- System Management
#include <avr/wdt.h>
uint8_t presc = WDTO_60MS;
// ---- ISD1820PY & Buzz
const byte play0 = 22;
const byte play1 = 23;
const byte LM386 = 25;
// i --> 0 1
const byte buzzer[2] = {13, 24}; // D13(PWM) & D24
// ---- DS3231
#include <DS3231.h>
DS3231 rtc(SDA, SCL); // init the DS3231 using the hardware interface
String strTM;
#define RTCArrSize 4
byte tm[RTCArrSize];
byte al[RTCArrSize];
bool alOn;
bool alActivated = 0; // temp variable, becomes high if al has been turned on, used for serial report
bool alActive = 0; // temp variable for TM and AL comparison, becomes high if these values match, and
// activates the alarm procedure by turning alCnt into 1.
byte alCnt = 0; // enables an alarm procedure whitch is longer than one minute, it increases until
// reach the alCntLim limit. One alCnt period equals to cycTmrInterval2, thats why takes 2400ms.
const byte alCntLim = 255;
// ---- VR3
bool vrOn;
const byte ledVrOn = 29;
#include <SoftwareSerial.h>
#include "VoiceRecognitionV3.h"
VR myVR(10, 11); // RX, TX
uint8_t record[7]; // save record
uint8_t buf[64];
byte group;
#define spkHeater (0)
#define spkAiring (1)
#define spkKitchen (2)
#define spkMedia (3)
#define spkDesklig (4)
#define spkSys (5)
#define spkTempr (6)
#define spk17 (7)
#define spk18 (8)
#define spk19 (9)
#define spk20 (10)
#define spk14 (11)
#define spk58 (12)
#define spkBack (13)
#define spkCost (14)
#define spkCost0 (15)
#define spkReport (16)
#define spkReboot (17)
#define spkTime (18)
#define spkDisc (19)
#define spkSilence (20)
// ---- Terminators & The Cleanup Crew
const char termCharNull = '0';
const char termChar = 'Z';
const char termCharSpc = ' ';
char termCharEmpty;
const String strTerm;
const int intTerm = 0;
const bool boolTerm = 0;
// ---- Startup
const uint8_t frame1[] U8G_PROGMEM = {
0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC0, 0x7F, 0x01, 0xC0, 0xBF,
0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0x02, 0x80,
0x7F, 0x01, 0xE0, 0xBF, 0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10,
0xB8, 0xFF, 0x02, 0xC0, 0x7F, 0x01, 0xC0, 0xBF, 0x2F, 0x08, 0x02, 0xFF,
0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0xFE, 0x9F, 0x7F, 0xFF, 0xFF, 0xBF,
0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC1,
0x7F, 0x81, 0xC0, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0xFE, 0xFF,
0xAF, 0xFF, 0x02, 0x81, 0x7F, 0x81, 0xE0, 0xBF, 0xD7, 0xFF, 0xFF, 0xFD,
0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC1, 0x7F, 0x81, 0xC0, 0xBF,
0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0x02, 0x81,
0x7F, 0x81, 0xE0, 0xBF, 0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10,
0xB8, 0xFF, 0x02, 0xC1, 0x7F, 0x81, 0xC0, 0xBF, 0x2F, 0x08, 0x02, 0xFF,
0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0x02, 0x81, 0x7F, 0x81, 0xE0, 0xBF,
0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC1,
0x7F, 0x81, 0xC0, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10,
0xA8, 0xFF, 0x02, 0x81, 0x7F, 0x81, 0xE0, 0xBF, 0x17, 0x08, 0x02, 0xFD,
0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC1, 0x7F, 0x81, 0xC0, 0xBF,
0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0x02, 0x81,
0x7F, 0x81, 0xE0, 0xBF, 0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10,
0xB8, 0xFF, 0xFE, 0xFF, 0x7F, 0xFF, 0xFF, 0xBF, 0x2F, 0x08, 0x02, 0xFF,
0xFF, 0xBF, 0x40, 0x10, 0xA8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE,
0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 0xB8, 0x7F, 0x00, 0x00,
0x00, 0x00, 0x00, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10,
0xA8, 0x7F, 0x00, 0x48, 0x22, 0x09, 0x00, 0xBF, 0x17, 0x08, 0x02, 0xFD,
0xFF, 0x7F, 0x41, 0x10, 0xB8, 0x7F, 0x20, 0x49, 0x22, 0x49, 0x02, 0xBF,
0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0xAA, 0xAA, 0xAA, 0x7F, 0x26, 0x49,
0x22, 0x49, 0x32, 0xBF, 0x57, 0x55, 0x55, 0xFD, 0xFF, 0x7F, 0x55, 0x55,
0xB5, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF, 0xAF, 0xAA, 0xAA, 0xFE,
0xFF, 0xBF, 0xAA, 0xAA, 0xAA, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF,
0x57, 0x55, 0x55, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F, 0x26, 0x49,
0x22, 0x49, 0x32, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xBF, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F, 0x26, 0x49,
0x22, 0x49, 0x32, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xBF, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x3F, 0x00, 0x49, 0x22, 0x49, 0x00, 0xBE,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
0x55, 0xD5, 0x55, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC,
0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x1F, 0xF0, 0xFF, 0x1F, 0xF0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0xFF, 0x0F, 0xE0, 0xFF,
0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xC0,
0xFF, 0x07, 0xC0, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x03, 0x80, 0xFF, 0x03, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0x03, 0xC0, 0xFF,
0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x80,
0xFF, 0x05, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFD, 0xDF, 0xFF, 0xFD, 0xDF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x81, 0xFF, 0x05, 0x81, 0xFF,
0x3F, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0xC1,
0xFF, 0x05, 0xC1, 0xFF, 0x7F, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x05, 0x81, 0xFF, 0x05, 0x81, 0xFF, 0x3F, 0x10, 0x04, 0xFF,
0xFF, 0xFF, 0x5F, 0xFD, 0xFF, 0xFF, 0x05, 0xC1, 0xFF, 0x05, 0xC1, 0xFF,
0x7F, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0x03, 0xE0, 0xFF, 0xFF, 0x05, 0x81,
0xFF, 0x05, 0x81, 0xFF, 0x3F, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0x79, 0x8F,
0xFF, 0xFF, 0x05, 0xC1, 0xFF, 0x05, 0xC1, 0xFF, 0x7F, 0x10, 0x04, 0xFF,
0xFF, 0xFF, 0x7C, 0x3F, 0xFF, 0xFF, 0x05, 0x81, 0xFF, 0x05, 0x81, 0xFF,
0x3F, 0x10, 0x04, 0xFF, 0xFF, 0x7F, 0x7E, 0x3F, 0xFE, 0xFF, 0x05, 0xC1,
0xFF, 0x05, 0xC1, 0xFF, 0x7F, 0x10, 0x04, 0xFF, 0xFF, 0x3F, 0x7D, 0xDF,
0xFC, 0xFF, 0x05, 0x81, 0xFF, 0x05, 0x81, 0xFF, 0x3F, 0x10, 0x04, 0xFF,
0xFF, 0x9F, 0x7B, 0xEF, 0xF9, 0xFF, 0x05, 0xC1, 0xFF, 0x05, 0xC1, 0xFF,
0x7F, 0x10, 0x04, 0xFF, 0xFF, 0x8F, 0x77, 0xF7, 0xF9, 0xFF, 0xFD, 0xFF,
0xFF, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0xFF, 0x9F, 0x6F, 0xFB,
0xF1, 0xFF, 0x01, 0x00, 0x55, 0x01, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0xFF,
0xFF, 0x8F, 0x5F, 0xFD, 0xF9, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE,
0xAF, 0xAA, 0xAA, 0xFA, 0xFF, 0x9F, 0x3F, 0xFE, 0xF1, 0x7F, 0x55, 0x55,
0x55, 0x55, 0x55, 0xFF, 0x57, 0x55, 0x55, 0xFD, 0xFF, 0x0F, 0x00, 0x00,
0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x9F, 0x7F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x7F, 0xFF,
0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0x8F, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
};
const uint8_t frame2[] U8G_PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0,
0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00,
0x1C, 0x00, 0x00, 0x00, 0xF0, 0x87, 0x1F, 0x00, 0x01, 0x30, 0x00, 0x00,
0x00, 0x3C, 0x00, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x00, 0xCE, 0x1F,
0x38, 0x80, 0x21, 0xC0, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x88,
0x80, 0x01, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x22, 0x80, 0x01, 0x00,
0x40, 0x80, 0x00, 0x00, 0x00, 0x10, 0x04, 0x03, 0x00, 0x40, 0x20, 0x40,
0x00, 0x01, 0x20, 0x01, 0x02, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x06, 0x00,
0x20, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x0C, 0x00, 0x30, 0xC0, 0x1F,
0x00, 0xC6, 0x7F, 0x00, 0x18, 0x00, 0x18, 0xE0, 0x7F, 0x80, 0xC3, 0xDF,
0x02, 0x3E, 0x00, 0x0C, 0xC0, 0xFF, 0x83, 0xF9, 0xFF, 0x02, 0x68, 0x00,
0x06, 0x00, 0xF0, 0x03, 0x1F, 0x01, 0xF0, 0xC1, 0x00, 0x6A, 0x00, 0x80,
0x00, 0x06, 0x07, 0xFC, 0x87, 0x01, 0x82, 0x0F, 0x80, 0x00, 0x00, 0x9E,
0x0F, 0x46, 0x01, 0xC2, 0xB9, 0x81, 0x00, 0x00, 0xF8, 0x21, 0x4C, 0x03,
0x02, 0xF0, 0xC1, 0x00, 0x00, 0x00, 0x70, 0x48, 0x02, 0x02, 0x04, 0x70,
0x00, 0x03, 0x00, 0x7C, 0x58, 0x02, 0x22, 0x06, 0x38, 0x00, 0x2F, 0x00,
0xCF, 0x5B, 0x02, 0x0E, 0x06, 0x1C, 0x00, 0x08, 0xC0, 0xC3, 0x49, 0x03,
0x16, 0x0F, 0x39, 0xF0, 0x09, 0xF8, 0x60, 0x08, 0x03, 0x4C, 0x0F, 0x60,
0x00, 0x0D, 0x5F, 0x70, 0x8C, 0x01, 0x08, 0x3F, 0xC0, 0x03, 0xE0, 0x43,
0x3C, 0x90, 0x01, 0x18, 0xF7, 0x80, 0x01, 0x7E, 0x60, 0x1F, 0xC0, 0x00,
0x18, 0xD7, 0x07, 0xF8, 0x3F, 0xF0, 0x1B, 0x70, 0x00, 0x10, 0x13, 0xFF,
0x7F, 0x30, 0xFC, 0x0C, 0x30, 0x00, 0x10, 0x97, 0xC1, 0x10, 0xA0, 0x7F,
0x04, 0x18, 0x00, 0x10, 0x9F, 0x41, 0x10, 0xF0, 0x4F, 0x06, 0x08, 0x00,
0x10, 0xFF, 0xEF, 0x38, 0xFF, 0x41, 0x03, 0x0C, 0x00, 0x10, 0xFF, 0xFF,
0xFF, 0x7F, 0xC0, 0x01, 0x04, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0x47, 0xC0,
0x00, 0x06, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0x40, 0x70, 0x00, 0x03, 0x00,
0x10, 0xEA, 0xFF, 0x67, 0xC0, 0x18, 0x00, 0x03, 0x00, 0x10, 0x5E, 0xC6,
0x60, 0x80, 0x0E, 0x80, 0x01, 0x00, 0x10, 0xCC, 0x84, 0x60, 0x80, 0x07,
0xE8, 0x00, 0x00, 0x10, 0xBC, 0x8C, 0x60, 0xF0, 0x21, 0x72, 0x00, 0x00,
0x18, 0xF0, 0x9F, 0xE1, 0x3F, 0x88, 0x18, 0x00, 0x00, 0x18, 0x00, 0xFF,
0xFF, 0x01, 0x22, 0x0E, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x80, 0x88,
0x07, 0x00, 0x00, 0x18, 0x08, 0x40, 0x01, 0x10, 0xC2, 0x01, 0x00, 0x00,
0x18, 0x20, 0x00, 0x00, 0x46, 0x78, 0x00, 0x00, 0x00, 0x18, 0x01, 0xFF,
0x0F, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x60, 0x80, 0x07,
0x00, 0x00, 0x00, 0x18, 0x30, 0xFE, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00,
0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xF0, 0x03, 0x00,
0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1F, 0xFE, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x1F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const uint8_t frame3[] PROGMEM = {
0xFF, 0xFF, // 11111111 11111111 00
0xFF, 0xFF, // 11111111 11111111 01
0xCF, 0xFF, // 11001111 11111111 02
0xC3, 0xFF, // 11000011 11111111 03
0xC0, 0xFF, // 11000000 11111111 04
0xC0, 0x3F, // 11000000 00111111 05
0xC0, 0x0F, // 11000000 00001111 06
0xC0, 0x03, // 11000000 00000011 07
0xC0, 0x0F, // 11000000 00001111 08
0xC0, 0x3F, // 11000000 00111111 09
0xC0, 0xFF, // 11000000 11111111 10
0xC3, 0xFF, // 11000011 11111111 11
0xCF, 0xFF, // 11001111 11111111 12
0xFF, 0xFF, // 11111111 11111111 13
};
const uint8_t frame4[] PROGMEM = {
0xFF, 0xFF, // 11111111 11111111 00
0xDF, 0xFB, // 11011111 11111011 01
0xEC, 0x37, // 11101100 00110111 02
0xF8, 0x1F, // 11111000 00011111 03
0xF0, 0x0F, // 11110000 00001111 04
0x90, 0x09, // 10010000 00001001 05
0xF0, 0x0F, // 11110000 00001111 06
0xF8, 0x1F, // 11111000 00011111 07
0xDC, 0x3B, // 11011100 00111011 08
0xBD, 0xBD, // 10111101 10111101 09
0xFC, 0x3F, // 11111100 00111111 10
0xFD, 0xBF, // 11111101 10111111 11
0xFE, 0x7F, // 11111110 01111111 12
0xFF, 0xFF, // 11111111 11111111 13
};
const uint8_t frame5[] PROGMEM = {
0xFF, 0xFF, // 11111111 11111111 00
0xFF, 0xFF, // 11111111 11111111 01
0xFC, 0x3F, // 11111100 00111111 02
0xF8, 0x1F, // 11111000 00011111 03
0xF0, 0x0F, // 11110000 00001111 04
0xF0, 0x0F, // 11110000 00001111 05
0xF0, 0x0F, // 11110000 00001111 06
0xF8, 0x1F, // 11111000 00011111 07
0xFC, 0x3F, // 11111100 00111111 08
0xFD, 0xBF, // 11111101 10111111 09
0xFC, 0x3F, // 11111100 00111111 10
0xFD, 0xBF, // 11111101 10111111 11
0xFE, 0x7F, // 11111110 01111111 12
0xFF, 0xFF, // 11111111 11111111 13
};
const uint8_t frame6[] PROGMEM = {
0xFF, 0xFF, // 11111111 11111111 00
0xFE, 0x7F, // 11111110 01111111 01
0xF8, 0x1F, // 11111000 00011111 02
0xF3, 0xCF, // 11110011 11001111 03
0xE7, 0xE7, // 11100111 11100111 04
0xEF, 0xF3, // 11101111 11110111 05
0xCF, 0xF3, // 11001111 11110011 06
0xC0, 0x03, // 11000000 00000011 07
0xC0, 0x03, // 11000000 00000011 08
0xC1, 0x83, // 11000001 10000011 09
0xC1, 0x83, // 11000001 10000011 10
0xC1, 0x83, // 11000001 10000011 11
0xC0, 0x03, // 11000000 00000011 12
0xFF, 0xFF, // 11111111 11111111 13
};
const uint8_t frame7[] PROGMEM = {
0xFF, 0xFF, // 11111111 11111111 00
0xFF, 0xFF, // 11111111 11111111 01
0xF3, 0xE7, // 11110011 11100111 02
0xF3, 0xE7, // 11110011 11100111 03
0xF3, 0xE7, // 11110011 11100111 04
0x80, 0x67, // 10000000 01100111 05
0x80, 0x67, // 10000000 01100111 06
0xF3, 0xE7, // 11110011 11100111 07
0xF3, 0xE7, // 11110011 11100111 08
0xF3, 0xC3, // 11110011 11000011 09
0xFF, 0x81, // 11111111 10000001 10
0xFF, 0x81, // 11111111 10000001 11
0xFF, 0xC3, // 11111111 11000011 12
0xFF, 0xE7, // 11111111 11100111 13
0xFF, 0xFF, // 11111111 11111111 14
};
const uint8_t frame8[] PROGMEM = {
0x00, 0x00, // 00000000 00000000 00
0x00, 0x00, // 00000000 00000000 01
0x0C, 0x18, // 00001100 00011000 02
0x0C, 0x18, // 00001100 00011000 03
0x0C, 0x18, // 00001100 00011000 04
0x7F, 0x98, // 01111111 10011000 05
0x7F, 0x98, // 01111111 10011000 06
0x0C, 0x18, // 00001100 00011000 07
0x0C, 0x18, // 00001100 00011000 08
0x0C, 0x3C, // 00001100 00111100 09
0x00, 0x7E, // 00000000 01111110 10
0x00, 0x7E, // 00000000 01111110 11
0x00, 0x3C, // 00000000 00111100 12
0x00, 0x18, // 00000000 00011000 13
0x00, 0x00, // 00000000 00000000 14
};
const uint8_t frame9[] PROGMEM = {
0xFF, 0xFF, // 11111111 11111111 00
0xFC, 0x1F, // 11111100 00011111 01
0xF0, 0x07, // 11110000 00000111 02
0xEE, 0x0B, // 11101110 00001011 03
0xE7, 0x1B, // 11100111 00011011 04
0xC3, 0x39, // 11000011 00111001 05
0xC1, 0x71, // 11000001 01110001 06
0xC0, 0x81, // 11000000 10000001 07
0xC7, 0x41, // 11000111 01000001 08
0xCE, 0x61, // 11001110 01100001 09
0xEC, 0x73, // 11101100 01110011 10
0xE8, 0x3B, // 11101000 00111011 11
0xF0, 0x07, // 11110000 00000111 12
0xFC, 0x1F, // 11111100 00011111 13
0xFF, 0xFF, // 11111111 11111111 14
};
const uint8_t frame10[] PROGMEM = {
0xFF, 0xFF, // 11111111 11111111 00
0xFC, 0x9F, // 11111100 10011111 01
0xF0, 0xC7, // 11110000 11000111 02
0xE0, 0xE3, // 11100000 11100011 03
0xE0, 0xE3, // 11100000 11100011 04
0xCC, 0xC1, // 11001100 11000001 05
0xDE, 0x81, // 11011110 10000001 06
0xFF, 0xFF, // 11111111 11111111 07
0xC0, 0xBD, // 11000000 10111101 08
0xC1, 0x99, // 11000001 10011001 09
0xE3, 0x83, // 11100011 10000011 10
0xE3, 0x83, // 11100011 10000011 11
0xF1, 0x87, // 11110001 10000111 12
0xFC, 0x9F, // 11111100 10011111 13
0xFF, 0xFF, // 11111111 11111111 14
};
const uint8_t frame11[] PROGMEM = {
0x1F, 0x03, 0x18, // 00011111 00000011 00011000 00
0x3B, 0x83, 0xB8, // 00111011 10000011 10111000 01
0x79, 0xC1, 0xF0, // 01111001 11000001 11110000 02
0xDA, 0xE0, 0xE0, // 11011010 11100000 11100000 03
0xEB, 0x61, 0xF0, // 11101011 01100001 11110000 04
0xF2, 0xE3, 0xB8, // 11110010 11100011 10111000 05
0xF9, 0xE3, 0x18, // 11111001 11100011 00011000 06
0xF2, 0xE0, 0x00, // 11110010 11100000 00000000 07
0xEB, 0x60, 0x00, // 11101011 01100000 00000000 08
0xDA, 0xE0, 0x00, // 11011010 11100000 00000000 09
0x79, 0xC0, 0x00, // 01111001 11000000 00000000 10
0x3B, 0x80, 0x00, // 00111011 10000000 00000000 11
0x1F, 0x00, 0x00, // 00011111 00000000 00000000 12
};
void setup() {
TM1637( 0, 0, 5);
readEEPROM();
rtc.begin();
irrecv.enableIRIn();
mySwitch.enableReceive(0); // receiver on D2 (interrupt 0)
SPI.begin(); // init SPI bus
rfid.PCD_Init(); // init MFRC522
pinMode(relayDL, OUTPUT);
pinMode(relayMP, OUTPUT);
pinMode(extBTen, OUTPUT);
digitalWrite(extBTen, 0);
pinMode(ledAuth, OUTPUT);
digitalWrite(ledAuth, 0);
pinMode(ledVrOn, OUTPUT);
for (byte i = 0; i < 2; i++) {
pinMode(buzzer[i], OUTPUT);
}
pinMode(play0, OUTPUT);
pinMode(play1, OUTPUT);
pinMode(LM386, OUTPUT);
pinMode(pwrRF, OUTPUT);
pinMode(btnAl, INPUT);
Serial.begin(9600);
Serial2.begin(9600); // start serial communication at 9600bps EXT
for (byte i = 0; i < exRXSize; i++) {
exRX[i] = termCharSpc;
}
Serial3.begin(9600); // INT
myVR.begin(9600);
voiceLoad(0);
ISD1820PY(0);
strSelector(0);
}
void loop() {
irRecv();
extRX();
cyclicSysTmr();
countdnSysTmr();
intRX();
btnRecv();
sevenSum();
voiceCmd();
rfRecv();
rfID();
u8g.firstPage(); // picture loop
do {
draw();
} while(u8g.nextPage());
if (frame == 0) {
TM1637(2, 0, 0);
delay(1000);
frame = 1;
clrScr();
}
}
// ---- System Management
void wdRst() {
wdt_enable(presc); // start wd with the prescaller
while(1) { // the prescaller time has to expire
}
}
void readEEPROM() {
for (byte i = 0; i < 6; i++) {
if (i < 4) {
al[i] = EEPROM.read(addr[i + 5]);
delay(20);
}
if (i == 5) {
i = 9;
}
switch(i) {
case 0:
lockSystem(EEPROM.read(addr[i]));
rfidHandler();
case 1:
// REMOVED FEATURE
case 2:
prntRTC = EEPROM.read(addr[i]);
case 3:
digitalWrite(relayDL, relayDLState = EEPROM.read(addr[i]));
break;
case 4:
digitalWrite(relayMP, relayMPState = EEPROM.read(addr[i]));
break;
case 9:
alOn = EEPROM.read(addr[i]);
delay(20);
i++;
digitalWrite(pwrRF, rfOn = EEPROM.read(addr[i]));
delay(20);
i++;
digitalWrite(ledVrOn, vrOn = EEPROM.read(addr[i]));
}
delay(20);
}
}
// ---- Start of System Security Routines
void rfID() {
if (cardManager) {
for (byte i = 0; i < arrNUIDSize; i++) {
if ((delNUID[i] == 1) && (strNUID[i] != strTerm)) {
strNUID[i] = strTerm;
delNUID[i] = boolTerm;
cardBoolSwitches[3] = 1; // del card
cardBoolSwitches[2] = 1; // not stored
TM1637( 3, 5, 0);
}
}
}
if (!rfid.PICC_IsNewCardPresent()) // wait for a new card
return;
if (!rfid.PICC_ReadCardSerial()) // check if the card has been readed
return;
cardBoolSwitches[0] = boolTerm; // the card has not been seen
strC = strTerm;
MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
if ((piccType != MFRC522::PICC_TYPE_MIFARE_MINI) && (piccType != MFRC522::PICC_TYPE_MIFARE_1K) && (piccType != MFRC522::PICC_TYPE_MIFARE_4K)) {
if (!cardManager) {
strSelector(34);
}
else {
cardBoolSwitches[6] = 1; // invalid type of card
ISD1820PY(1);
}
return;
}
for (byte i = 0; i < rfid.uid.size; i++) {
strC.concat(String(rfid.uid.uidByte[i] < 0x10 ? " 0" : " "));
strC.concat(String(rfid.uid.uidByte[i], HEX));
}
strC = strC.substring(1);
if (cardManager) {
if (strNUID[3].charAt(0) != termCharEmpty) {
cardBoolSwitches[7] = 1; // memory full
TM1637( 3, 8, 0);
return;
}
for (byte i = 0; i < arrNUIDSize; i++) {
if (strC == strNUID[i]) { // maybe the readed card has been stored earlier
cardBoolSwitches[4] = 1; // already stored
TM1637( 3, 7, 0);
}
}
if (!cardBoolSwitches[4]) {
for (byte i = 0; i < arrNUIDSize; i++) {
if ((strNUID[i] == strTerm) && (!cardBoolSwitches[0]) && (strC != strTerm)) { // if there is a space for the new card, but only one space needed, if the reading strC isnt empty
strNUID[i] = strC;
cardBoolSwitches[5] = 1; // card new
cardBoolSwitches[0] = 1; // card seen (because we want only one time to store)
cardBoolSwitches[2] = 1; // card NOT stored yet
TM1637( 3, 6, 0);
}
}
}
}
else {
for (byte i = 0; i < arrNUIDSize; i++) {
if (strNUID[i] == strC) {
lockSystem(!locked);
strSelector(36);
extTX(1);
}
}
if ((locked) && (strNUID[0] != strC) && (strNUID[1] != strC) && (strNUID[2] != strC) && (strNUID[3] != strC)) {
strSelector(35);
extTX(1);
ISD1820PY(1);
}
}
rfid.PICC_HaltA(); // halt PICC
rfid.PCD_StopCrypto1(); // stop encryption on PCD
}
void rfidHandler() {
if (cardBoolSwitches[1]) { // read at startup
pointer = addr[12];
for (byte i = 0; i < arrNUIDSize; i++) {
strNUID[i] = (EEPROM.get(pointer, arrNUID[i]));
delay(20);
pointer = pointer + addr[13];
}
cardBoolSwitches[1] = boolTerm;
}
if (cardBoolSwitches[2]) { // not stored yet or marked for delete
buzz(0, 13, 1, 0);
for (byte i = 0; i < (arrNUIDSize - 1); i++) { // sort
if (strNUID[i] == strTerm) {
strNUID[i] = strNUID[i + 1];
strNUID[i + 1] = strTerm;
}
}
pointer = addr[12];
for (byte i = 0; i < arrNUIDSize; i++) {
strNUID[i].toCharArray(arrNUID[i], strNUID[i].length() + 1); // conv str to ch array
strNUID[i] = (EEPROM.put(pointer, arrNUID[i]));
delay(40);
pointer = pointer + addr[13];
}
cardBoolSwitches[2] = boolTerm;
}
}
void lockSystem(bool op) { // 0: unlock, 1: lock
bool prevState = locked;
EEPROM.write(addr[0], op);
delay(40);
locked = EEPROM.read(addr[0]);
delay(20);
if (locked) {
cardManager = boolTerm;
sum = intTerm;
relayHandlerDL(boolTerm);
relayHandlerMP(boolTerm);
}
if (locked != prevState) {
extTX(0);
}
intTX(0, lock_strings[locked]);
}
// ---- Start of 315/330/433MHz Receiver
void rfRecv() {
if ((locked) || (!pwrRF)) {
return;
}
if (mySwitch.available()) {
if (mySwitch.getReceivedValue() != 0) {
// btn 'A' - Airing
// <-- ADDR 2^20 | DATA 2^4 -->
if (mySwitch.getReceivedValue() == 5592332) { // 010101010101010100001100
delay(50); // TRI-STATE FFFFFFFF0010
if (!onlink) { // RAW 16972,524,1664,1576,572,516,1656,1596,556,544,1644,1604,556,508,1660,1584,580,528,1648,1588,552,540,1648,1596,564,500,1668,1576,576,516,1668,1596,548,516,1664,508,1668,532,1656,500,1672,1592,576,1552,640,464,1676,504,1664,
strSelector(21); // PulseLength: 545 microseconds Protocol: 1
}
else {
intTX(0, 42);
strSelector(5);
}
} // btn 'B' - Kitchen lights
if (mySwitch.getReceivedValue() == 5592512) { // 010101010101010111000000
delay(50); // FFFFFFFF1000
if (!onlink) { // 16952,528,1644,1596,532,524,1648,1588,564,528,1636,1596,544,512,1656,1588,564,508,1652,1580,568,516,1656,1580,552,508,1664,1552,612,476,1680,1584,540,1584,568,1588,564,508,1656,528,1644,524,1656,500,1668,508,1664,504,1672,
strSelector(21); // PulseLength: 546 microseconds Protocol: 1
}
else {
intTX(0, 82);
strSelector(5);
}
} // btn 'C' - Media player
if (mySwitch.getReceivedValue() == 5592323) { // 010101010101010100000011
delay(50); // FFFFFFFF0001
relayHandlerMP(2); // 16980,532,1640,1588,580,504,1660,1608,540,536,1648,1608,540,516,1656,1580,588,496,1676,1596,552,536,1636,1580,588,488,1688,1580,560,520,1664,1564,592,484,1672,512,1668,516,1668,520,1652,504,1664,536,1644,1608,564,1584,556,
strSelector(5); // PulseLength: 546 microseconds Protocol: 1
} // btn 'D' - Desklights
if (mySwitch.getReceivedValue() == 5592368) { // 010101010101010100110000
delay(50); // FFFFFFFF0100
relayHandlerDL(2); // 16996,528,1644,1596,544,508,1664,1576,584,496,1668,1568,580,536,1644,1588,560,500,1660,1564,604,484,1708,1580,524,524,1652,1580,568,532,1656,1580,556,508,1668,512,1668,1576,568,1600,552,508,1672,520,1672,484,1676,504,1664,
strSelector(5); // PulseLength: 546 microseconds Protocol: 1
}
}
mySwitch.resetAvailable();
}
}
// ---- Start of Matrix Handler Sequence
void btnRecv() {
// --------------------- Accepted Keys on Main Screen --------------------------------------------------------------------
//
// -- Remote appliances:
// 'A' : Airing On / Off
// 'B' : Kitchen lights On / Off
// '*' : Heater On / Off (15 min timed mode)
//
// -- Local appliances:
// 'C' : Media player On / Off
// 'D' : Desklights On / Off
//
// -- Other functions:
// '0' .. '9' : Enter Numeric Code command such as Target Temperature for
// the Thermostat mode [10-24 (as Celsius) or 50-76 (as Fahrenheit)],
// or two-digit control code to access the attached home devices or system functions (see details below).
// --> '*': Delete the typed code, and go back to the Main Screen
// --> '#': Enter code
//
// [by pressing first time] [second time] [third time]
// '0' : Print RTC on LCD On --> Print both RTC & Alarm on LCD, and turn Alarm On --> Dismiss both
//
// '#' : Enter the RFID handler menu
// --> 'A' : Delete pos 0
// --> 'B' : Delete pos 1
// --> 'C' : Delete pos 2
// --> 'D' : Delete pos 3
// --> '#' : Exit RFID menu and go back to the Main Screen
// -----------------------------------------------------------------------------------------------------------------------
if (digitalRead(btnAl)) {
delay(50);
alOn = !alOn;
EEPROM.write(addr[9], alOn);
delay(40);
TM1637(0, 0, 1);
buzz(0, 12, 10, 1);
}
char customKey = customKeypad.getKey();
if (customKey != NO_KEY) {
if (alCnt > 0) {
alOn = boolTerm;
EEPROM.write(addr[9], alOn);
delay(40);
alCnt = alCntLim;
TM1637( 0, 0, 1);
strSelector(59);
return;
}
buzz(0, 22, 4, 0);
if (group != 0) {
group = 0;
return;
}
if ((customKey == '0') && (!cardManager) && (sum == intTerm)) {
TMandALmanager();
return;
}
if (locked) {
strSelector(70);
return;
}
if ((customKey == '#') && (sum == intTerm)) { // rfid menu
if (!cardManager) {
TM1637( 3, 4, 0);
}
cardManager = !cardManager;
if (!cardManager) {
TM1637( 0, 0, 1);
}
}
if (cardManager) {
switch (customKey) {
case 'A':
delay(50);
delNUID[0] = 1;
break;
case 'B':
delay(50);
delNUID[1] = 1;
break;
case 'C':
delay(50);
delNUID[2] = 1;
break;
case 'D':
delay(50);
delNUID[3] = 1;
break;
}
}
else {
switch (customKey) {
case 'A':
delay(10);
if (!onlink) {
strSelector(21);
}
else {
strSelector(6);
intTX(0, 42);
}
break;
case 'B':
delay(10);
if (!onlink) {
strSelector(21);
}
else {
strSelector(6);
intTX(0, 82);
}
break;
case 'C':
delay(10);
strSelector(6);
relayHandlerMP(2);
break;
case 'D':
delay(10);
strSelector(6);
relayHandlerDL(2);
break;
case '*':
delay(10);
if (sum > intTerm) { // del the numeric code
sum = intTerm;
}
else {
if (!onlink) {
strSelector(21);
}
else {
intTX(0, 32);
}
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
delay(10);
if ((sum <= 10) && (sum <= 99)) {
sum = sum * 10 + (customKey - '0');
}
break;
case '#':
delay(10);
if (sum == 25) {
intTX(0, sum);
delay(100);
wdRst();
return;
}
if (sum == 26) {
rfOn = !rfOn;
digitalWrite(pwrRF, rfOn);
EEPROM.write(addr[10], rfOn);
delay(40);
if (rfOn) {
strSelector(63);
}
else {
strSelector(64);
}
}
if (sum == 27) {
vrOn =! vrOn;
digitalWrite(ledVrOn, vrOn);
EEPROM.write(addr[11], vrOn);
delay(40);
if (vrOn) {
strSelector(68);
}
else {
strSelector(69);
}
}
if (sum == 28) {
sum = intTerm;
if (auth) {
scr();
strSelector(71);
extTX(3);
}
else {
strSelector(72);
}
}
...
This file has been truncated, please download it to see its full contents.
// ---- THERMOSTAT PROGRAM CODE v2.0
// Program code of an intelligent Arduino smarthome thermostat solution,
// based on Arduino Nano (or higher) board, DS18B20 thermo sensor, HC-05 Bluetooth adapter, I2C 128X64 bicolor OLED display.
// The system can be controlled by buttons and Android smartphone via bluetooth.
//
// It handles the HEATER gas boiler, the bathroom AIRING ventilator and the kitchen LIGHTING - swithed with relays.
// The heater has two working ways. 1: One Time Heating (15 mins) timed mode, 2: Thermostat mode (higher priority). The adjusted target tempr.
// stored in EEPROM. The program detects hardware errors and window opening - in these cases the heater stops and/or will not start.
//
// Designed and programmed
// by Gyula Osi.
// All rights reserved.
// ------------------------------------------------------------------------------------------------------------------------------------
// ---- Display I2C BUS, SDA(TX) -> A4, SCL(RX) -> A5
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); // display constructor
byte frame = 0; // scr pointer
// ---- Ports and Related Declarations
const byte buzzer = 9; // buzzer to D9
int btnVal; // stores analog values from buttons
const byte relayA = 11; // airing
bool aStateByCmd; // if "window alert" is gone, the airing control goes back to the original state
bool aState = 0;
const byte relayL = 13; // lighting
bool lState = 0;
const byte relayH = 10; // heater
const byte ledH = 6; // PWM ports allow output level adjustment [2^8] used to change brightness
const byte ledA = 5;
const byte ledL = 3;
const byte bright[3] = {0, 10, 100};
byte brightHeat = bright[2];
#define ledInterval 1000 // heater led blinking interval
unsigned long prev = 0;
// ---- Strings for Display Printout and Bluetooth Reports
#define STATE_ITEMS 3 // device state indicator strings for outputs
// i -> 0 1 2
const String state_str[STATE_ITEMS] = {"on.", "off.", "auto."};
String heaterState;
String airingState;
String lightingState;
#define FUNCT_ITEMS 22
// i -> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
const String funct_str[FUNCT_ITEMS] = {"Heater is ", "Airing is ", "Lighting is ", "Window Alert!", "Hardware Error!", "Hit a Key >>", "or send a Code!", "Target = ", "Temperature = ", " * ", " -", "> ", "REPORT", "Celsius mode", "Fahrenheit mode", "System ", "un", "locked!", "Command rejected!", "X", "cost= ", "USD"};
// ---- Memory Management
#include <EEPROM.h>
const byte addr[4] = { 0, 1, 2, 3}; // ---- Memory Map
// [i] STORED
// 0 byte tTarget
// 1 bool celsius
// 2 bool locked
// 3 int costMinutes, initial address [int: 2^16]
// ---- Temperature and Heater Related Features
#include <elapsedMillis.h>
elapsedMillis timer0; // 8-bit, PWM timer, used by function elapsedMillis()
#define sftyTmrInterval 15 * 60000 // one Time Heating (15 mins) timed mode interval [ms]
bool sftyTmrEnded; // boolean startup, the timer0 has ended
byte tTarget; // adjusted target tempr
bool celsius; // measurement unit; 0 = F, 1 = C
float heatCorrVal; // declares the degree of overheating and cooling back, see tempMeas() function
#define mUnit 2
#define tRef 2
#define corr 3
const float hCorrRef[mUnit][tRef] = {{62.6, 66.2}, {17, 19}};
const float hCorrVal[mUnit][corr] = {{0.9, 0.72, 0.54}, {0.5, 0.4, 0.3}};
bool hState = 0; // heater boolean state
bool hStatePrev = 0; // previous heater boolean state
bool hThermostat = 0; // thermostat boolean state
#include "OneWire.h"
#include "DallasTemperature.h"
#define DS18B20 2 // setup the OneWire bus on D2
OneWire temprWire(DS18B20); // setup DS18B20 to work on the OneWire bus
DallasTemperature sensors(&temprWire);
float tempr; // measured value
float temprPrev; // copy of measured value for trend analysis
float temprStart; // copy of measured value for summary of a heating period
bool windowAlrt = 0; // specified degree of tempr drop
#define aVal 3 // drop/lift/under
const float wAlrt[mUnit][aVal] = {{ 0.36, -0.216, 68}, { 0.2, -0.12, 20}};
// = {{ 0.36, 0.2}, {-0.216, -0.12}, {68, 20}};
bool measError = 0; // measured tempr value is out of the range specified as normal
bool errMsgSentBySys = 0; // do not flood
const long temprInterval = 60000; // cyclic tempr measurement interval [ms]
unsigned long temprTmrPrev = 0; // the elapsed will be the previous when temprMeas() called
bool sysChanged = 0; // this bool will high, if the tempr meas system has changed recently (C2F/F2C),
// so the tempr analisys won't start due to the unappropriate temprPrev value
bool hPeriodFin = 0; // writeout the summary after a heating period
int costMinutes; // minute counter stored in EEPROM
int minutes = 0; // minute counter for summary of a heating period
// |<-- cost of 1 min -->|
// |<-- USD/m^3 -->|
float costCoeff = ((10.52 / 28.31685) / 50); // based on the U.S. average annual natural gas residental price; $10.52 / 1000ft^3 (www.eia.gov)
float cost; // 1000ft^3 = 28.31685m^3, and my boiler uses up 1m^3 natural gas in 50 minutes
// ---- System & Security
#include <avr/wdt.h>
uint8_t presc = WDTO_15MS;
bool locked;
bool startup = 1; // keep avoid a duplicate BT report at startup if the system is locked
// ---- Configuration of Serial Communication on virtual RXD/TXD [D8/D4]
#include <SoftwareSerial.h>
const int RX1 = 8;
const int TX1 = 4;
SoftwareSerial sUART(RX1,TX1);
char RX[2]; // store received serial data
#define rprtInterval 1000 // sending interval of the Cyclic Binary Synchronous Report
unsigned long prevRprt = 0; // (please see details & the structure on the bottom of the code)
bool sent = 0;
bool onlink = 0;
// ---- Terminators & The Cleanup Crew
const char charTerm = 'Z';
const bool boolTerm = 0;
const int intTerm = 0;
const uint8_t frame1[] U8G_PROGMEM = { // XBM map
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFE, 0xFF,
0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFC, 0xFF, 0x7F, 0xF0,
0x3F, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x00,
0xFC, 0xFF, 0x7F, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF,
0xFF, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF,
0x8F, 0xFF, 0x1F, 0x7F, 0x8C, 0x3F, 0x1E, 0xFF, 0x00, 0xFE, 0x1F, 0xFF,
0xF1, 0x00, 0x18, 0xC0, 0x8F, 0xFF, 0x1F, 0x7F, 0x8C, 0x3F, 0x1E, 0xFF,
0x00, 0xFE, 0x1F, 0xFF, 0xF1, 0x00, 0x18, 0xC0, 0x8F, 0xFF, 0x1F, 0x1F,
0x0C, 0x3E, 0x1E, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0x31, 0xFE, 0x7F, 0xFC,
0x8F, 0xFF, 0x1F, 0x1F, 0x0C, 0x3E, 0x1E, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF,
0x31, 0xFE, 0x7F, 0xFC, 0x0F, 0x0E, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0xFC,
0x00, 0xF8, 0x1F, 0x7C, 0x30, 0xFE, 0x7F, 0xF0, 0x0F, 0x0E, 0x18, 0x1F,
0x0C, 0x3E, 0x1E, 0xFC, 0x00, 0xF8, 0x1F, 0x7C, 0x30, 0xFE, 0x7F, 0xF0,
0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C,
0xF0, 0x00, 0x7E, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C,
0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x00, 0x7E, 0xF0, 0x0F, 0xFE, 0x18, 0x1F,
0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0,
0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C,
0xF0, 0x3F, 0x78, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C,
0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 0x0F, 0xFE, 0x18, 0x1F,
0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0,
0x3F, 0x00, 0x7E, 0x00, 0x3C, 0x80, 0x07, 0xF0, 0x00, 0xF8, 0x7F, 0x00,
0x3C, 0x00, 0x1E, 0xC0, 0x3F, 0x00, 0x7E, 0x00, 0x3C, 0x80, 0x07, 0xF0,
0x00, 0xF8, 0x7F, 0x00, 0x3C, 0x00, 0x1E, 0xC0, 0xFF, 0xFF, 0xFF, 0x1F,
0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7E, 0x06, 0xE6, 0x3F, 0x06, 0xC6, 0x7F, 0xFE, 0xE7, 0x3F, 0x7E,
0xFE, 0xC7, 0x7F, 0x00, 0x00, 0x30, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00,
0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0x06, 0x66,
0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00,
0x00, 0x30, 0x1E, 0x66, 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x30,
0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0x3E, 0x66, 0x60, 0x06, 0x66, 0x00,
0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xE6,
0x61, 0x1E, 0xC7, 0x3F, 0x70, 0xE0, 0x3F, 0x3C, 0xFE, 0xC3, 0x3F, 0x00,
0x00, 0x3C, 0x7E, 0xE6, 0x61, 0x1E, 0xC7, 0x3F, 0x70, 0xE0, 0x3F, 0x3C,
0xFE, 0xC3, 0x3F, 0x00, 0x00, 0x3C, 0xDE, 0xE7, 0x61, 0x1E, 0x07, 0x70,
0x70, 0xE0, 0x1D, 0x3C, 0x1E, 0x00, 0x70, 0x00, 0x00, 0x3C, 0x1E, 0xE7,
0x61, 0x1E, 0x07, 0x70, 0x70, 0xE0, 0x31, 0x3C, 0x1E, 0x00, 0x70, 0x00,
0x00, 0x3C, 0x1E, 0xE6, 0x61, 0x1E, 0x07, 0x70, 0x70, 0xE0, 0x61, 0x3C,
0x1E, 0x00, 0x70, 0x00, 0x00, 0x3C, 0x1E, 0xE6, 0x61, 0x1E, 0x07, 0x70,
0x70, 0xE0, 0x61, 0x3C, 0x1E, 0x00, 0x70, 0x00, 0x00, 0x7F, 0x1E, 0xE6,
0x3F, 0xFC, 0xE3, 0x3F, 0x70, 0xE0, 0x61, 0x7E, 0xFE, 0xE7, 0x3F, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
const uint8_t frame2[] PROGMEM = {
0xFF,0xFF, // 11111111 11111111 00
0xFF,0xFF, // 11111111 11111111 01
0xFE,0x7F, // 11111110 01111111 02
0xF8,0x1F, // 11111000 00011111 03
0xF3,0xCF, // 11110011 11001111 04
0xE7,0xE7, // 11100111 11100111 05
0xEF,0xF3, // 11101111 11110111 06
0xCF,0xF3, // 11001111 11110011 07
0xC0,0x03, // 11000000 00000011 08
0xC0,0x03, // 11000000 00000011 09
0xC1,0x83, // 11000001 10000011 10
0xC1,0x83, // 11000001 10000011 11
0xC1,0x83, // 11000001 10000011 12
0xC1,0x83, // 11000001 10000011 13
0xC0,0x03, // 11000000 00000011 14
0xC0,0x03, // 11000000 00000011 15
0xFF,0xFF, // 11111111 11111111 16
0xFF,0xFF, // 11111111 11111111 17
};
void setup() {
sUART.begin(9600);
pinMode(relayH, OUTPUT);
relayHandlerH(4); // get the working state
pinMode(ledH, OUTPUT);
pinMode(relayA, OUTPUT);
relayHandlerA(4);
pinMode(ledA, OUTPUT);
pinMode(relayL, OUTPUT);
relayHandlerL(4);
pinMode(ledL, OUTPUT);
pinMode(buzzer, OUTPUT);
sensors.begin(); // start DS18B20
tTargetHandler(EEPROM.read(addr[0])); // Read the previously stored tTarget value from the current address of the EEPROM at startup
// First the tempMeas() will be called by tTargetHandler() by getting the appropriate tTarget
// value readed from the EEPROM. Later the temprMeas() will do it.
lockSystem(EEPROM.read(addr[2]));
costCalc(0);
startup = boolTerm;
}
void loop() {
temprTimer();
btRecv();
ledHandler();
binaryReport();
btnReadings();
safetyTmr();
u8g.firstPage(); // display loop
do {
draw();
}
while(u8g.nextPage());
if (frame == 0) {
delay(3000);
frame = 1;
clrScr();
}
}
void costCalc(bool op) { // 0 = read, 1 = write
if (!op) {
costMinutes = EEPROM.get(addr[3], costMinutes);
delay(20);
cost = costMinutes * costCoeff;
}
else {
EEPROM.put(addr[3], (costMinutes + minutes));
delay(80);
}
}
void lockSystem(bool op) {
bool prevState = locked;
EEPROM.write(addr[2], op);
delay(40);
locked = EEPROM.read(addr[2]);
delay(20);
if (locked) {
startup = 1;
windowAlrt = boolTerm;
relayHandlerH(0);
relayHandlerA(0);
relayHandlerL(0);
startup = boolTerm;
}
if (locked != prevState) {
sTX(12);
}
}
// ---- System Management
void wdRst() {
asm volatile ("jmp 0");
//wdt_disable(); // the WDT method works only on boards with new bootloader
//wdt_enable(presc); // start wd with the prescaller
//while(1) { // the prescaller time has to expire
//}
}
void btnReadings() { // --------- btn readings
if (locked) {
return;
}
btnVal = analogRead(A0); // read analog val from A0
if (btnVal >= 510 && btnVal <= 516) { // btn Lighting
delay(100); // btn debounce
buzz(3, 1);
relayHandlerL(2); // call proper function with logical state flip opcode as parameter
}
else if (btnVal >= 849 && btnVal <= 853){ // btn Airing
if (windowAlrt) { // if the system is in Window Alert mode, disable it
windowAlrt = boolTerm;
buzz(4, 3);
relayHandlerA(3);
}
else { // else turn on/off the airing ventilator
delay(100);
buzz(3, 1);
relayHandlerA(2);
}
}
else if (btnVal >= 927 && btnVal <= 933) { // btn One Time Heating (15 mins) timed mode
delay(100);
buzz(3, 1);
relayHandlerH(2);
}
else if (btnVal >= 767 && btnVal <= 777) { // btn decrease tTarget
delay(100);
tTargetHandler(0);
}
else if (btnVal >= 687 && btnVal <= 697) { // btn increase tTarget
delay(100);
tTargetHandler(1);
}
else if (btnVal >= 855 && btnVal <= 862) { // inc & dec btns at the same time will change
delay(100); // the unit of temperature measurement.
tTargetHandler(2); // flip measurement unit and convert the tempr target value
}
}
void btRecv() { // ------------- Receive Serial Data
while (sUART.available() > 0) { // if data is available to read
for (byte i = 0; i < 2; i++) {
RX[i] = sUART.read();
}
}
int iRX[2];
for (byte i = 0; i < 2; i++) {
iRX[i] = RX[i] - '0';
}
if (iRX[0] * 10 + iRX[1] == 98) {
lockSystem(0);
}
if (!locked) {
switch (RX[0]) { // ------------- Accept SINGLE ALPHABETICAL control codes
case 'A':
relayHandlerH(1); // 1=on
break;
case 'a':
relayHandlerH(0); // 0=off
break; // Received serial data can be a single alphabetical letter from "Arduino
case 'B': // Bluetooth Control Device" Android app. If a proper alphabetical
relayHandlerA(1); // character arrives, the program code will not wait for the second one,
break; // but calls the applicable function with a proper operation code.
case 'b': // Cases of combined numeric data can be seen below.
relayHandlerA(0);
break;
case 'C':
relayHandlerL(1);
break;
case 'c':
relayHandlerL(0);
break;
case 'D':
case 'd':
tTargetHandler(21);
buzz(3, 1);
break;
case 'E':
case 'e':
tTargetHandler(19);
buzz(3, 1);
break;
case 'F':
case 'f':
tTargetHandler(14);
buzz(3, 1);
break;
case 'R': // call for an overview report about controlled devices
case 'r':
if (windowAlrt) {
windowAlrt = boolTerm;
buzz(4, 3);
relayHandlerA(3);
}
else {
sTX(8);
sTX(2);
buzz(5, 2);
}
break;
case 'W': // disable Window Alert state
case 'w':
windowAlrt = boolTerm;
buzz(4, 3);
relayHandlerA(3);
break;
case '+':
tTargetHandler(0);
break;
case '-':
tTargetHandler(1);
break;
case 'l':
lockSystem(1);
break;
case 'X': // accept a request and send back a report
case 'x':
onlink = 1;
break;
case 'Y':
case 'y':
sTX(16);
break;
}
// -------------------------------------- Accept COMBINED NUMERIC Control Codes
// In this case a two-digit numeric control code arrives in char format, from an Android
// bluetooth serial app for instance. After a char to integer conversion
// (only if the first char is '1', '2', '5', '6', '7') a merge-process will follow, and the
// system of conditions and statements will make a decision and execute it.
//
// -------------------------- System Control Codes:
//
// 94: query for natural gas cost value
// 95: erase the cost value
// 96: lock the Thermostat Unit - arrives from the Central Unit (RFID)
// 97: unlock the Thermostat Unit - arrives from the Central Unit (RFID)
// 98: query for report of the devices (heater, airing, lights), and target temperature
// 99: sent by the Central Unit, activates the Onlink mode on the Thermostat Unit
//
// -------------------------- Device Control Codes:
// First = device code, Second = operator code
//
// 30, 31, 32 turns the heater: 30=off, 31=on, 32=flip logical state (on -> off / off -> on)
// One Time Heating (15 mins) timed heater program
// 40, 41, 42 will do the same to the airing ventilator
// 80, 81, 82 handles the kitchen lights as above
//
// 90, 91, 92 desklights (on the Central Unit only)
// 93 media player flip boolean state (on the Central Unit only)
//
// -------------------------- Classified Operator Codes:
// X3, X4 are classified, used only for function calls by inner program sequences
//
// -------------------------- Target Temperature:
// 10 - 24 as Celsius, or 50 - 76 as Fahrenheit values will be accepted and stored in EEPROM as
// target temperature for the thermostat function. If the measurement unit changes, the system
// converts all the previous temperature values (used for trend analisys, and summary statistics),
// and calls tempMeas() to make a new measurement in the actual unit.
switch (iRX[0]) {
case 3:
relayHandlerH(iRX[1]);
break;
case 4:
relayHandlerA(iRX[1]);
break;
case 8:
if ((iRX[1] >= 0) && (iRX[1] <= 4)) {
relayHandlerL(iRX[1]);
}
break;
case 9:
switch (iRX[1]) {
case 4:
sTX(16);
break;
case 5:
costMinutes = intTerm;
costCalc(1);
sTX(16);
break;
case 6:
sTX(8);
sTX(2);
break;
case 7:
lockSystem(1);
break;
}
default:
if (((iRX[0] * 10 + iRX[1] <= 24) && (iRX[0] * 10 + iRX[1] >= 10)) || ((iRX[0] * 10 + iRX[1] >= 50) && (iRX[0] * 10 + iRX[1] <= 76))) {
tTargetHandler(iRX[0] * 10 + iRX[1]);
buzz(3, 1);
}
if (iRX[0] * 10 + iRX[1] == 25) {
buzz(3, 1);
wdRst();
}
break;
}
}
if (iRX[0] * 10 + iRX[1] == 97) {
lockSystem(1);
}
if (iRX[0] * 10 + iRX[1] == 99) {
onlink = 1;
}
for (byte i = 0; i < 2; i++) {
RX[i] = charTerm;
}
}
void relayHandlerL(byte lOperator) { // lighting handler sequence
// operators are: 0=off, 1=on, 2=flip the state,
// 4=fill/refill the lighting state string var.
if ((measError) && ((lOperator == 1) || (lOperator == 2))) {
sTX(4);
return;
}
if ((lOperator == 2) || (lOperator == 0) && (lState) || (lOperator == 1) && (!lState)) {
lState = !lState;
digitalWrite(relayL, lState);
buzz(2, 1);
}
if (lOperator >= 0) { // fill up the working state char with the proper state indicator string
if (lState) {
lightingState = state_str[0];
}
else {
lightingState = state_str[1];
}
if ((!startup) && (!measError)) {
sTX(7);
}
}
}
void relayHandlerA(byte aOperator) { // airing handler sequence
// operators are: 0=off, 1=on, 2=flip the state,
if ((measError) && ((aOperator == 1) || (aOperator == 2))) { // operators are: 0=off, 1=on, 2=flip the state,
sTX(4); // 3=called by temprMeas() funct., 4=fill/refill the airing state char var.
return;
}
aState = digitalRead(relayA);
if (!windowAlrt) {
if ((aOperator == 2) || (aState) && (aOperator == 0) || (!aState) && (aOperator == 1)) {
aState = !aState;
digitalWrite(relayA, aState);
aStateByCmd = digitalRead(relayA);
buzz(2, 1);
}
}
if (aOperator == 3) { // called by the temprMeas() function, 'windowAlrt' ended or started
if ((!aState) && (windowAlrt) || (aState) && (!windowAlrt) && (!aStateByCmd)) {
digitalWrite(relayA, windowAlrt);
}
}
aState = digitalRead(relayA);
if (aOperator >= 0) {
if (aState) {
if (windowAlrt) {
airingState = state_str[2];
}
else {
airingState = state_str[0];
}
}
else {
airingState = state_str[1];
}
}
if ((!startup) && (!measError)) {
sTX(6);
}
}
void relayHandlerH(byte hOperator) { // heater handler sequence
// operators are: 0=off, 1=on, 2=flip the state,
// 3=called by temprMeas() funct., 4=fill/refill the heater state char var.
if ((measError) && ((hOperator == 1) || (hOperator == 2))) {
sTX(4);
return;
}
hStatePrev = hState;
if ((!hThermostat) && (!windowAlrt) && (!measError)) { // turn on/off the One Time Heating (15 mins) timed mode
if ((hOperator == 2) || (hOperator == 1) && (!hState) || (!hOperator) && (hState)) {
buzz(2, 1);
hState = !hState;
sftyTmrEnded = boolTerm;
timer0 = 0;
digitalWrite(relayH, hState);
}
}
if (windowAlrt) {
sTX(3);
}
if (hOperator == 3) { // this function called by the temprMeas() function (op 3)
// in order to examine windowAlrt & measError booleans extreme tempr values
if ((windowAlrt) && (hState)) { // a window is open and the heater is running
digitalWrite(relayH, 0);
buzz(5, 3);
}
if ((!windowAlrt) && (!measError)) {
if ((hThermostat) || (!hThermostat) && (hState) && (sftyTmrEnded)) {
digitalWrite(relayH, hThermostat); // proceed the command of the thermostat routine
}
}
}
hState = digitalRead(relayH);
if (hOperator >= 0) {
if (hState) {
if (hThermostat) {
heaterState = state_str[2];
}
else {
heaterState = state_str[0];
}
}
else {
heaterState = state_str[1];
}
}
// <------------------------------------------------------------------------------------------------------------------------------------>
// <--------------------------> <-----------------------------> <----------------------------> <------------------------------------------> <-------------->
if ((!measError) && (((!windowAlrt) && (!startup)) && (((hOperator == 0) && (!hState)) || ((hOperator == 1) && (hState)) || ((hOperator == 2) && (hState == hStatePrev)) || (hOperator == 4))) || (hState != hStatePrev)) {
sTX(5);
}
if (hState) {
minutes++;
}
if (hState != hStatePrev) {
if (hState) {
minutes = intTerm;
temprStart = tempr;
}
else {
costCalc(1);
sTX(14);
sTX(16);
hPeriodFin = 1;
}
}
}
void safetyTmr () { // timer for the One Time Heating (15 mins) timed mode
if (locked) {
return;
}
if ((hState) && (!sftyTmrEnded) && (timer0 > sftyTmrInterval) && (!hThermostat)) {
sftyTmrEnded = 1;
relayHandlerH(0);
for (byte i = 1; i < 5; i++) {
buzz(i, 2);
}
}
}
void temprTimer() { // cyclic timer for temprMeas()
unsigned long temprTmrCurr = millis();
if (temprInterval <= temprTmrCurr - temprTmrPrev) {
temprTmrPrev = temprTmrCurr;
hPeriodFin = boolTerm;
temprMeas();
}
}
void temprMeas() { // ----------- Tempr Measurement & Comparison Sequence
temprPrev = tempr; // save the value for next comparison
sensors.requestTemperatures(); // update sensor readings
if (celsius) {
tempr = sensors.getTempCByIndex(0); // read remperature
}
else {
tempr = sensors.getTempFByIndex(0);
}
if (((celsius) && ((tempr >= 40) || (tempr <= 0))) || ((!celsius) && ((tempr >= 104) || (tempr <= 32)))) {
if (!errMsgSentBySys) { // -127, -196.60 are HW errors, +85 is tipically SW error, but
sTX(4); // can be fire, or a broken window
}
errMsgSentBySys = 1;
hThermostat = boolTerm;
if (hState) {
relayHandlerH(0);
}
if (aState) {
relayHandlerA(0);
}
if (lState) {
relayHandlerL(0);
}
measError = 1;
for (byte i = 1; i < 10; i++) {
buzz(4, 1);
delay(50);
}
}
else {
measError = boolTerm;
errMsgSentBySys = boolTerm;
}
if (!measError) { // --------------- Start of Temperature Analysis Sequence
// Frequent, short-term switching of the heater gas boiler would cut short its lifetime, the
// heatCorrVal value helps to keep avoid it. Declares the degree of overheating and cooling back.
// Lower temperature demands greater heatCorrVal, because the walls are colder and adsorb better the
// warmth from the freshly heated-up air, so the above described effect would more stronger.
if (tempr <= hCorrRef[celsius][0]) {
heatCorrVal = hCorrVal[celsius][0];
}
if ((tempr > hCorrRef[celsius][0]) && (tempr < hCorrRef[celsius][1])) {
heatCorrVal = hCorrVal[celsius][1];
}
if (tempr >= hCorrRef[celsius][1]) {
heatCorrVal = hCorrVal[celsius][2];
}
if (!sysChanged) { // If the meas system has changed recently, dont start the temp analisys for the first time
if (tTarget - tempr >= heatCorrVal) { // subtract measured value from target, if the difference equals or greater than heatCorrVal
sftyTmrEnded = 1; // deactivate the One Time Heating (15 mins) timed program if it is running
hThermostat = 1; // turn on the thermostat
buzz(1, 1);
}
if ((tTarget - tempr <= -1 * heatCorrVal) && (hThermostat)) {
hThermostat = boolTerm;
}
if ((!windowAlrt) && (temprPrev - tempr >= wAlrt[celsius][0]) && (tempr <= wAlrt[celsius][2])) {
windowAlrt = 1; // in a measurement cycle and in heating season the temperature
sftyTmrEnded = 1; // drops, it will evaluate as a window is open
for (byte i = 1; i < 5; i++) {
buzz(4, 1);
delay(50);
}
relayHandlerA(3); // call airing function (opcode = 3), to help refresh the air
}
if ((windowAlrt) && (temprPrev - tempr <= wAlrt[celsius][1])) {
windowAlrt = boolTerm; // the tempr. falling is over, the air became warmer
buzz(4, 3); // due to the heat capacity of the environment,
relayHandlerA(3); // so switch back to normal mode
}
relayHandlerH(3); // the function will examine caller param(3) & windowAlrt & measError booleans
} // ---- end of sysChanged section
if (!windowAlrt) {
sTX(1);
}
}
sysChanged = boolTerm;
}
void tTargetHandler (byte set) { // -------------- Start of Target Temperature handler routine
hPeriodFin = boolTerm;
if (set == 0) {
if (((celsius) && (tTarget < 24)) || ((!celsius) && (tTarget < 76))) {
tTarget++ ; // ------------------ Set of Operator Codes -------------------------
tTargetEEPROM(); // 0 : INCR
buzz(3, 1); // 1 : DECR tTarget until it reaches the max / min limit
} // 2 : FLIP mesurement unit, and converts the stored tTarget
else { // value into the appropriate unit. This function also converts
buzz(2, 3); // temprPrev and temprStart values. Called by btnReadings()
} // if the INCR & DECR buttons has been pressed at the same time.
tTargetEEPROM(); // 10..24 & 50..76: intervals received from Bluetooth, adding the
} // tTarget value, and the examination of tTargetHandler()
if (set == 1) { // will declare the unit of the measurement.
if (((celsius) && (tTarget > 10)) || ((!celsius) && (tTarget > 50))) {
tTarget-- ;
tTargetEEPROM();
buzz(3, 1);
}
else {
buzz(2, 3);
}
tTargetEEPROM();
}
if (set == 2) {
if (celsius) {
tTarget = ((1.8 * tTarget) + 32), 0;
temprPrev = ((1.8 * temprPrev) + 32), 2;
if (hState) {
temprStart = ((1.8 * temprStart) + 32), 2;
}
}
else {
tTarget = ((5 * (tTarget - 32)) / 9), 0;
temprPrev = ((5 * (temprPrev - 32)) / 9), 2;
if (hState) {
temprStart = ((5 * (temprStart - 32)) / 9), 2;
}
}
sysChanged = 1;
celsius = !celsius;
temprMeas(); // after set, call the EEPROM handler function, and write the tTarget value to the appropriate byte of the EEPROM
tTargetEEPROM(); // target tempr has changed, call the temp meas function, don't wait for the cyclic timer
}
celsius = EEPROM.read(addr[1]);
if (((set >= 10) && (set <= 24)) || ((set >= 50) && (set <= 76))) {
tTarget = set;
if ((tTarget <= 24) && (!celsius)) {
sysChanged = 1;
celsius = 1;
if (hState) {
temprStart = (5 * (temprStart - 32)) / 9;
}
temprPrev = (5 * (temprPrev - 32)) / 9;
sTX(10);
}
if ((tTarget >= 50) && (celsius)) {
sysChanged = 1;
celsius = 0;
if (hState) {
temprStart = (1.8 * temprStart) + 32;
}
temprPrev = (1.8 * temprPrev) + 32;
sTX(9);
}
tTargetEEPROM();
temprMeas();
}
}
void tTargetEEPROM() {
EEPROM.write(addr[0], tTarget); // after incr/decr/set, write the tTarget value to the appropriate byte of the EEPROM
delay(40);
EEPROM.write(addr[1], celsius);
delay(40);
sTX(2);
}
void draw(void) {
if (frame == 0)
u8g.drawXBMP( 0, 0, 128, 64, frame1);
else if (frame == 1)
screenFunctState();
}
void screenFunctState(void) { // function state screen
temprWriteOut(0, 64);
u8g.drawHLine(0, 46, 128);
u8g.setFont(u8g_font_unifont);
if (!windowAlrt) {
u8g.setPrintPos( 0, 14);
u8g.print(funct_str[0]);
u8g.setPrintPos(84, 14);
u8g.print(heaterState);
}
else {
u8g.setPrintPos( 0, 14);
u8g.print(funct_str[3]);
}
if (!locked) {
u8g.setPrintPos( 0, 28);
u8g.print(funct_str[1]);
u8g.setPrintPos(88, 28);
u8g.print(airingState);
u8g.setPrintPos( 0, 42);
u8g.print(funct_str[2]);
u8g.setPrintPos(95, 42);
u8g.print(lightingState);
}
else {
sysLckWriteOut();
}
if ((!hState) && (!aState) && (!lState)) {
screenStndby(); // if all of controlled devices are in off, call standby screen
}
}
void screenStndby() { // standby scr
u8g.firstPage();
do {
u8g.setFontRefHeightText();
u8g.setFont(u8g_font_unifont);
if (measError) {
u8g.setPrintPos( 4, 64);
u8g.print(funct_str[4]);
}
else {
if (hPeriodFin) {
byte y = 48;
u8g.setPrintPos(4, y);
u8g.print(minutes);
u8g.setPrintPos(26, y);
u8g.print("min & ");
if (tempr > temprStart) {
u8g.setPrintPos(68, y);
u8g.print("+");
}
u8g.setPrintPos(80, y);
u8g.print(tempr - temprStart);
if (celsius) {
u8g.setPrintPos(114, y);
u8g.print(char(176));
u8g.setPrintPos(120, y);
u8g.print("C");
}
else {
u8g.setPrintPos(114, y);
u8g.print("F");
}
costCalc(0);
u8g.setPrintPos( 8, y + 16);
u8g.print(funct_str[20]);
u8g.setPrintPos( 62, y + 16);
u8g.print(cost, 2);
u8g.setPrintPos(104, y + 16);
u8g.print(funct_str[21]);
}
else {
if (locked) {
sysLckWriteOut();
}
else {
u8g.setPrintPos(33, 52);
u8g.print(funct_str[5]);
u8g.setPrintPos( 8, 64);
u8g.print(funct_str[6]);
}
}
}
temprWriteOut(0, 16);
} while(u8g.nextPage());
}
void temprWriteOut (int tX, int tY) { // draw tempr & tTarget variables onto different coordinates
u8g.setPrintPos(tX, tY);
u8g.setFont(u8g_font_unifont);
char buftTarget[9];
sprintf (buftTarget, "%d", tTarget); // int to char conversion
u8g.drawStr(tX, tY, buftTarget);
u8g.setPrintPos(tX + 18, tY);
u8g.print(funct_str[9]); // tX + 18
u8g.setPrintPos(tX + 50, tY); // tX + 32
u8g.print(tempr); // printing temp.
if (celsius) {
u8g.print(char(176));
u8g.print("C");
}
else {
u8g.print("F");
}
}
void sysLckWriteOut() {
u8g.drawBitmapP(0, 22, 2, 18, frame2);
u8g.drawHLine( 16, 22, 112);
u8g.drawHLine( 16, 39, 112);
u8g.drawVLine(127, 22, 17);
u8g.setPrintPos(19, 36);
u8g.print(funct_str[15]);
u8g.setPrintPos(71, 36);
u8g.print(funct_str[17]);
}
void clrScr(){
u8g.firstPage();
do {
} while(u8g.nextPage());
}
void ledHandler() { // the brightHeat of a led is low, if the indicated device is off, and high, if its on
if (!locked) {
if (aState) {
analogWrite(ledA, bright[2]);
}
else {
analogWrite(ledA, bright[1]);
}
if (lState) {
analogWrite(ledL, bright[2]);
}
else {
analogWrite(ledL, bright[1]);
}
if (hState) {
if (!hThermostat) {
ledBlnk() ; // the heater led blinks when the One Time Heating (15 mins) timed mode is activated,
}
else {
brightHeat = bright[2] ; // and constant bright, if the thermostat routine is active
}
}
else {
brightHeat = bright[1] ;
}
analogWrite(ledH, brightHeat);
}
else {
analogWrite(ledL, bright[0]);
analogWrite(ledA, bright[0]);
analogWrite(ledH, bright[0]);
}
}
...
This file has been truncated, please download it to see its full contents.
Comments