// rgb matrix display - 64x32 envirinmental display
// Library written by Limor Fried/Ladyada & Phil Burgess/PaintYourDragon
// for Adafruit Industries.
// BSD license, all text above must be included in any redistribution.
// John Saunders 4/23/2020 Garage fan change, added clear notification
// John Saunders 5/20/2020 added 4 more fields from the solar Sensor r message
// 5/7/2020. Key OF for night page. Added Bluetooth Speaker and Girl Fountain Pump notification
// Flashing and Bullseye notifications were interchanged. Magenta for door "UP"
// 5/29/2021 Bullseye changed to Missions
// Mike Mitchell's advice is much appreciated
#include <RGBmatrixPanel.h>
#include <Wire.h> //I2C library
#define TRUE 1
#define FALSE 0
// ************************************** hardware definitions ******************************
// ************************************** the rgb matrix ************************************
#define CLK 11 // Using an ARDUINO MEGA 2560
#define OE 9
#define LAT 10
#define A A0
#define B A1
#define C A2
#define D A3
RGBmatrixPanel matrix(A, B, C, D, CLK, LAT, OE, true, 64); // For Mega with its 8K RAM
// ************************************** data acquisition ***********************************
// ************************************** External data from the Picax **********************
// The Picaxe sub-assembly gets sensor values from several remote sources via 433 MHz transmissions
// I consolidates them into a single message and sends that to the Arduino, via I2C
// The Picaxe is in Master mode, since it does not do slave
#define megaReady 19 // This pin controls Picaxe = Arduino communications
#define I2Caddr 0x07
// ************************************** External data storage **********************
typedef struct {
char modeCommand;
char event;
char tDate[6];
char tTime[6];
char sTemp[4];
char sHum[4];
char sMA[4];
char battV[5];
char gTemp[5];
char aPress[6];
char chgVolt[5];
byte discretes;
} eData_t;
eData_t eData = { 'G', 'z', {"02/67"}, {"05:30"}, {"033"}, {"026"}, {"077"}, {"6.45"}, {"456"}, {"29.56"}, {"12.3"}};
/int num_byte;
/ ************************************** function called on message received ***********************************
volatile int loopCount;
char BLZ(char c) { // Some leading zeroes are blanked for appearance purposes
char rv = c;
if (c == '0') {
rv = ' ';
}
return rv;
}
void receiveEvent(int HowMany) {
Serial.println(loopCount);
num_byte = Wire.available();
Serial.println(num_byte);
char m = Wire.read();
digitalWrite(megaReady, LOW);
if ((m >= 'A') && (m <= 'G')) {
eData.modeCommand = m;
}
else {
eData.modeCommand = 'J';
}
eData.event = Wire.read();
eData.tDate[0] = BLZ(Wire.read()); eData.tDate[1] = Wire.read();
eData.tDate[3] = Wire.read(); eData.tDate[4] = Wire.read();
eData.tTime[0] = BLZ(Wire.read()); eData.tTime[1] = Wire.read();
eData.tTime[3] = Wire.read(); eData.tTime[4] = Wire.read();
eData.sTemp[0] = BLZ( Wire.read()); eData.sTemp[1] = Wire.read(); eData.sTemp[2] = Wire.read();
eData.sHum[0] = BLZ(Wire.read()); eData.sHum[1] = Wire.read(); eData.sHum[2] = Wire.read();
eData.sMA[0] = BLZ(Wire.read()); eData.sMA[1] = Wire.read(); eData.sMA[2] = Wire.read();
eData.battV[0] = Wire.read(); eData.battV[2] = Wire.read(); eData.battV[3] = Wire.read();
eData.gTemp[0] = BLZ(Wire.read()); eData.gTemp[1] = Wire.read(); eData.gTemp[2] = Wire.read();
eData.aPress[1] = Wire.read(); eData.aPress[3] = Wire.read(); eData.aPress[4] = Wire.read();
eData.chgVolt[0] = BLZ(Wire.read()); eData.chgVolt[1] = Wire.read(); eData.chgVolt[3] = Wire.read();
eData.discretes = Wire.read();
if (eData.aPress[1] > '5') {
eData.aPress[0] = '2';
}
else {
eData.aPress[0] = '3';
}
loopCount = 0;
}
// ************************************** Internal HIH6130 temperature-humidity sensor ******************************
byte iHum, iTemp; // Sensor values in integer go here
byte fetch_humidity_temperature()
{
float RH, T_C;
byte address, Hum_H, Hum_L, Temp_H, Temp_L, _status;
unsigned int H_dat, T_dat;
address = 0x27;;
Wire.beginTransmission(address);
Wire.endTransmission();
delay(100);
Wire.requestFrom((int)address, (int) 4);
Hum_H = Wire.read();
Hum_L = Wire.read();
Temp_H = Wire.read();
Temp_L = Wire.read();
Wire.endTransmission();
_status = (Hum_H >> 6) & 0x03;
Hum_H = Hum_H & 0x3f;
H_dat = (((unsigned int)Hum_H) << 8) | Hum_L;
T_dat = (((unsigned int)Temp_H) << 8) | Temp_L;
T_dat = T_dat / 4;
RH = (float) H_dat * 6.10e-3;
iHum = (byte)RH;
T_C = (float) T_dat * 1.007e-2 - 40.0;
iTemp = (byte) ((T_C * 1.8) + 32);
return (_status);
}
// ************************************** Optional diagnostic printout ******************************
void printout(void) {
int i;
// char c;
Serial.print("Mode=");
Serial.print(eData.modeCommand, BIN);
Serial.print(",Event=");
Serial.println(eData.event);
Serial.print((char*)eData.tDate);
Serial.print(',');
Serial.println((char*)eData.tTime);
Serial.print("Outside Temperature=");
Serial.print((char*)eData.sTemp);
Serial.print(",Outside Humidity=");
Serial.print((char*)eData.sHum);
Serial.print(",Atmospheric pressure=");
Serial.println((char*)eData.aPress);
Serial.print("Solar Current=");
Serial.print((char*)eData.sMA);
Serial.print(",Battery Voltage=");
Serial.print((char*)eData.battV);
Serial.print(",Charging Voltage=");
Serial.println((char*)eData.chgVolt);
Serial.print("Garage Temperature=");
Serial.print((char*)eData.gTemp);
}
// ************************************** Text colors and dimming ******************************
int brightness; // part of index into the color taqble
#define lDim 2
#define lNormal 0
#define lBright 1
#define ulLimit 130
#define llLimit 70
typedef struct {
uint8_t rVal;
uint8_t gVal;
uint8_t bVal;
} SM_RGB;
enum colorList {black, red, blue, magenta, green, yellow, cyan, white};
// color table -- black, red, green, yellow, blue, magenta, cyan, white
// Three different intensities, normal, bright, dim.Color is 5-6-5
const SM_RGB colorTable[] = {
{ 32, 32, 32}, {100, 0, 0}, { 0, 100, 0}, {100, 100, 0},
{ 0, 0, 84}, {100, 0, 100}, { 0, 100, 100}, {100, 100, 100},
{ 64, 64, 64}, {255, 0, 0}, { 0, 255, 0}, {255, 255, 0},
{ 0, 0, 255}, {255, 0, 255}, { 0, 255, 255}, {255, 255, 255},
{ 0, 0, 0}, {32, 0, 0}, { 0, 32, 0}, {32, 32, 0},
{ 0, 0, 16}, {32, 0, 32}, { 0, 32, 32}, {32, 32, 32}
};
uint16_t getColorVal(byte colorIndex) {
uint16_t colorVal;
int tableIndex = (8 * brightness) + colorIndex;
colorVal = (((colorTable[tableIndex].rVal) & 0xf8) << 8) |
(((colorTable[tableIndex].gVal) & 0xfc) << 3) |
(((colorTable[tableIndex].bVal) & 0xf8) >> 3);
return colorVal;
}
// ************************************** Page Formatting ******************************
typedef struct {
byte fCol; // column to left
byte fRow; // top row
byte fColor; // character color
char *fData;
} item_t;
byte hotColor;
item_t pageA[11] = {{ 0, 0, white, eData.tTime}, { 35, 0, white, eData.tDate},
{ 5, 8, green, "-"}, { 0, 8, green, "E"}, { 9, 8, green, "Temp"}, { 37, 8, white, eData.sTemp}, { 59, 8, magenta, "F"},
{ 5, 16, green, "-"}, { 0, 16, green, "I"}, { 9, 16, green, "Temp"}, { 59, 16, magenta, "F"}
};
item_t pageB[11] = {{ 0, 0, white, eData.tTime}, { 35, 0, white, eData.tDate},
{ 5, 8, green, "-"}, { 0, 8, green, "E"}, { 9, 8, green, "Hum"}, { 37, 8, green, eData.sHum}, { 59, 8, green, "%"},
{ 5, 16, green, "-"}, { 0, 16, green, "I"}, { 9, 16, green, "Hum"}, { 59, 16, magenta, "%"}
};
item_t pageC[7] = {{ 0, 0, white, eData.tTime}, { 35, 0, white, eData.tDate},
{ 0, 8, white, eData.aPress}, { 36, 8, magenta, "inHg"},
{ 0, 16, magenta, "Solar"}, {34, 16, white, eData.sMA}, { 53, 16, cyan, "MA"},
};
item_t pageD[11] = {{5, 0, green, "-"}, { 0, 0, green, "G"}, { 9, 0, green, "Fan"},
{ 5, 8, green, "-"}, { 0, 8, green, "G"}, { 9, 8, green, "Temp"}, {37, 8, hotColor, eData.gTemp}, { 59, 8, green, "F"},
{ 5, 16, green, "-"}, { 0, 16, green, "G"}, { 10, 16, green, "Door"}
};
item_t pageE[8] = {{ 0, 0, red, eData.tTime}, { 35, 0, red, eData.tDate},
{ 0, 8, green, "Batt"}, { 34, 8, white, eData.battV}, { 59, 8, green, "V"},
{ 0, 16, green, "Charg"}, {34, 16, white, eData.chgVolt}, { 59, 16, green, "V"}
};
item_t pageG[1] = {20, 12, blue, eData.tTime};
item_t pageJ[4] = {{ 0, 0, red, "Made In"}, { 0, 8, red, "2019 By"}, { 0, 16, red, "John"}, { 0, 24, red, "Saunders"}
};
item_t *f;
void dispStrng(int i) { // For strings defined in page arrays
matrix.setTextColor(getColorVal(f->fColor));
matrix.setCursor(f->fCol, f->fRow);
matrix.print(f->fData);
}
void dispNum(int col, int row, byte color, int dat) { // For binary values
matrix.setTextColor(getColorVal(color));
matrix.setCursor(col, row);
matrix.print(dat, DEC);
}
// ************************************** Notifications ******************************
// The notification is in two parts, unit and command, per the universal control
// 0 1 2 3 4 5 6 7
const char *unitStr[] = {"Shelf", "Flash", "Temps", "Cube", "Pole", "Circle", "Eggs", "Hang",
"Hums", "Solar", "Pineaple", "Ceiling", "Missions", "Floor", "Gate", "Door", "Clear", "Speaker", "Pump"
};
// 8 9 10 11 12 13 14 15 16 17 18
// 0 1 2 3 4 5 6 7 8 9
const char *actStr[] = {"On", "Off", "Down", "Red", "Blue", "Siren", "Green", "Open", "Shut", "Up"};
typedef struct {
char cmd;
byte firstIndx;
byte sndIndx;
} note_t;
note_t notifications[] = { {'e', 3, 4}, {'D', 3, 6}, {'H', 3, 1}, {'Q', 14, 7}, {'B', 14, 8}, {'A', 3, 3}, {'Y', 1, 0}, {'W', 1, 1}, {'P', 5, 0}, {'l', 5, 1},
{'d', 6, 0}, {'9', 6, 1}, {'M', 12, 0}, {'g', 12, 1}, {'R', 11, 0}, {'G', 11, 1}, {'I', 7, 0}, {'C', 7, 1}, {'h', 3, 6}, {'8', 10, 1},
{'K', 10, 0}, {'k', 4, 1}, {'i', 4, 0}, {'f', 13, 1}, {'b', 13, 0}, {'F', 0, 1}, {'E', 0, 0}, {'m', 16, 0}, {'J', 16, 1}, {'U', 17, 1}, {'S', 17, 0},
{'T', 18, 1}, {'j', 18, 0}, {'z', 0, 0}
};
void dispNot(void) {
byte indx = 0;
// byte firstIndx;
// byte secondIndx;
while ((eData.event != notifications[indx].cmd) && (notifications[indx].cmd != 'z')) {
indx++;
}
if (notifications[indx].cmd != 'z') {
matrix.setTextColor(getColorVal(red));
matrix.setCursor(0, 24);
matrix.print((char *)unitStr[notifications[indx].firstIndx]);
matrix.print(' ');
matrix.print((char *)actStr[notifications[indx].sndIndx]);
}
}
// ************************************** Setup and Loop ******************************
void setup() {
Serial.begin(9600);
matrix.begin();
matrix.setTextWrap(false); // Allow text to run off right edge
matrix.setTextSize(0);
matrix.fillScreen(0); // Clear background
Wire.begin(I2Caddr);
Wire.onReceive(receiveEvent);
pinMode(megaReady, OUTPUT);
digitalWrite(megaReady, LOW);
loopCount = 0;
eData.modeCommand = 'C';
delay(1000);
}
// Pick apart the mode command
#define cmdMask 0x07
#define doorMask 0x08
#define hotMask 0x10
#define fanMask 0x20
#define tAgeMask 0x40
#define sAgeMask 0x80
void loop() {
byte _status;
if (loopCount == 2) {
digitalWrite(megaReady, HIGH);
}
if (loopCount == 1) {
_status = fetch_humidity_temperature();
}
brightness = lNormal;
matrix.fillScreen(0); // Clear background
switch (eData.modeCommand) {
case 'C':
if ((eData.discretes & tAgeMask) > 0) {
pageA[0].fColor = red;
}
else {
pageA[0].fColor = white;
}
if ((eData.discretes & sAgeMask) > 0) {
pageA[5].fColor = red;
}
else {
pageA[5].fColor = white;
}
for (int i = 0; i < 11; i++) {
f = &pageA[i];
dispStrng(i);
}
matrix.drawCircle(56, 9, 1, getColorVal(magenta));
matrix.drawCircle(56, 17, 1, getColorVal(magenta));
dispNum( 37, 16, white, iTemp);
dispNot();
break;
case 'D':
for (int i = 0; i < 11; i++) {
f = &pageB[i];
dispStrng(i);
}
dispNum( 37, 16, white, iHum);
dispNot();
break;
case 'E':
for (int i = 0; i < 9; i++) {
f = &pageC[i];
dispStrng(i);
}
dispNot();
break;
case 'A':
if ((eData.discretes & hotMask) > 0) {
pageD[6].fColor = red;
}
else {
pageD[6].fColor = blue;
}
for (int i = 0; i < 11 ; i++) {
f = &pageD[i];
dispStrng(i);
}
matrix.drawCircle(56, 9, 1, getColorVal(green));
matrix.setCursor (38, 16);
if ((eData.discretes & doorMask) > 0) {
matrix.setTextColor(getColorVal(magenta));
matrix.print("Up");
}
else {
matrix.setTextColor(getColorVal(green));
matrix.print("Down");
}
matrix.setCursor (32, 0);
if ((eData.discretes & fanMask) > 0) {
matrix.setTextColor(getColorVal(red));
matrix.print("Run");
}
else {
matrix.setTextColor(getColorVal(green));
matrix.print("Stop");
}
dispNot();
break;
case 'B':
for (int i = 0; i < 10; i++) {
f = &pageE[i];
dispStrng(i);
}
dispNot();
break;
case 'F':
default:
f = &pageG[0];
dispStrng(0);
break;
}
delay(200);
matrix.swapBuffers(true);
loopCount++;
if (loopCount > 300) {
loopCount = 0;
}
}