Photon Based Open Source Thermostat

I would like to share project I’m working on right now. It is Photon based Thermostat:
It has next specifications:

  • 24VAC/DC Power
  • 4 Relay Outputs
  • 1 Analog 0-10V Output
  • Temperature Sensor
  • Optional Humidity
  • 128x128 TFT Screen
  • Dial Operational Button
  • ABS Plastic Enclosure

Right now I’m working on Arduino GFX port for my TFT screen!

10 Likes

Sweet!

Here is a graphing library that I came across that you may want to use in your project.

@peekay123 is going to work on making it Photon friendly.

1 Like

Thanks , my screen may be small for graphs but I will try it out.

This is awesome. I’ve been using a Raspberry Pi mounted behind a 15" touchscreen panel to control my furnace for a few years by the Pi’s GPIO pins. I’ve got a second Photon that I eventually plan to replace the control part with - this looks very similar to what I was envisioning!

Raspberry Pi is running my furnace as well, only I’m using HVAC control system I developed based on RPi.

Take a look on http://www.cube-controls.com/pi-cubes

@RWB, I have the code running on the 2.7" SharpMem display and it looks good. The way the code it written, it can’t be part of the mfGFX library as it needs to work with the display-specific driver library. This is why the first parameter passed is display object which is created with the display library constructor. Bottom line is that it needs to live in the user code, as a single function. :wink:

@peekay123 So the graphing code needs no changes to work with the Particle devices, we just need to drop it into out user code which contains the library for what ever screen were using? If so that sounds great!

@RWB, just a couple of things I need to look at but basically, yes, that would be the idea AS LONG AS you use a GFX or mfGFX-based display.

1 Like

I managed to compile it with some changes , still have to set up correct parameters to get graph fit my screen resolution!

@RWB, here is the code to run the demo on the 2.7" Sharpmem display. Note that I used a hardware SPI version (my adaptation) of the Sharpmem library.

/*********************************************************************
This is an example sketch for our Monochrome SHARP Memory Displays
*********************************************************************/
#include "Adafruit_mfGFX.h"
#include "Adafruit_SharpMem.h"
#include "math.h"

// This #include statement was automatically added by the Spark IDE.
//#include "glcdfont.h"


SYSTEM_MODE(SEMI_AUTOMATIC);

Adafruit_SharpMem sharp(A3, A5, A2);    //HARDWARE SPI - SCK, MOSI, SS

#define BLACK 0
#define WHITE 1

// this is the only external variable used by the graph
// it's a flat to draw the coordinate system only on the first pass
boolean display = true;

//double ox , oy ;

void Graph(Adafruit_SharpMem &d, double x, double y, double gx, double gy, double w, double h, double xlo, double xhi, double xinc, double ylo, double yhi, double yinc, String title, String xlabel, String ylabel, unsigned int gcolor, unsigned int acolor, unsigned int pcolor, unsigned int tcolor, unsigned int bcolor, boolean &redraw);

void setup(void) 
{
	double x, y;

	sharp.init();       // Initialize the hardware ports since cannot be done in class instantation above
	Serial.begin(9600);

	//Default font is ARIAL_8, uncomment line below to set to different font
	//display.setFont(TIMESNR_8);

	// start & clear the display
	sharp.begin();
	sharp.clearDisplay();

	for (x = 0; x <= 6.3; x += .1) {
		y = sin(x);
		Graph(sharp, x, y, 60, 230, 330, 200, 0, 6.5, 1, -1, 1, .25, "Sin Function", "x", "sin(x)", BLACK, BLACK, BLACK, BLACK, WHITE, display);
	}
	sharp.refresh();
	delay(2000);

	sharp.clearDisplay();
	display = true;
	for (x = 0; x <= 6.3; x += .1) {

		y = sin(x);
		Graph(sharp, x, y, 100, 235, 200, 200, 0, 6.5, 3.25, -1, 1, .25, "Sin Function", "x", "sin(x)", BLACK, BLACK, BLACK, BLACK, WHITE, display);
	}
	sharp.refresh();
	delay(2000);

	sharp.clearDisplay();
	display = true;
	for (x = 0; x <= 25.2; x += .1) {
		y = sin(x);
		Graph(sharp, x, y, 50, 190, 340, 60, 0, 25, 5, -1, 1, .5, "Sin Function", "x", "sin(x)", BLACK, BLACK, BLACK, BLACK, WHITE, display);
	}
	sharp.refresh();
	delay(2000);

	sharp.clearDisplay();
	display = true;
	for (x = 0.001; x <= 10; x += .1) {
		y = log(x);
		Graph(sharp, x, y, 50, 230, 300, 180, 0, 10, 1, -10, 5, 1, "Natural Log Function", "x", "ln(x)", BLACK, BLACK, BLACK, BLACK, WHITE, display);
	}
	sharp.refresh();
	delay(2000);
	
	sharp.clearDisplay();
	display = true;
	for (x = 0; x <= 10; x += 1) {
		y = x * x;
		Graph(sharp, x, y, 40, 230, 350, 200, 0, 10, 1, 0, 100, 10, "Square Function", "x", "x^2", BLACK, BLACK, BLACK, BLACK, WHITE, display);
	}
	sharp.refresh();
	delay(2000);

	sharp.clearDisplay();
	display = true;
	for (x = 0.00; x <= 20; x += .01) {
		y = ((sin(x)) * x + cos(x)) - log(x);
		Graph(sharp, x, y, 40, 230, 350, 200, 0, 20, 1, -20, 20, 5, "Weird Function", "x", " y = sin(x) + cos(x) - log(x)", BLACK, BLACK, BLACK, BLACK, WHITE, display);
	}
	sharp.refresh();
	delay(2000);

	sharp.clearDisplay();
	display = true;
	for (x = 0; x <= 12.6; x += .1) {
		y = sin(x);
		Graph(sharp, x, y, 40, 230, 150, 150, 0, 13, 3.5, -1, 1, 1, "Sin(x)", "x", "sin(x)", BLACK, BLACK, BLACK, BLACK, WHITE, display);
	}
	sharp.refresh();
	delay(2000);

	sharp.clearDisplay();
	display = true;
	for (x = 0; x <= 6.3; x += .05) {
		y = cos(x);
		Graph(sharp, x, y, 50, 230, 340, 200, 0, 6.5, 3.25, -1, 1, 1, "Cos Function", "x", "cos(x)", BLACK, BLACK, BLACK, BLACK, WHITE, display);
	}
	sharp.refresh();
}

void loop(void) 
{

}

/*
function to draw a cartesian coordinate system and plot whatever data you want
just pass x and y and the graph will be drawn

huge arguement list
&d name of your display object
x = x data point
y = y datapont
gx = x graph location (lower left)
gy = y graph location (lower left)
w = width of graph
h = height of graph
xlo = lower bound of x axis
xhi = upper bound of x asis
xinc = division of x axis (distance not count)
ylo = lower bound of y axis
yhi = upper bound of y asis
yinc = division of y axis (distance not count)
title = title of graph
xlabel = x asis label
ylabel = y asis label
gcolor = graph line colors
acolor = axi ine colors
pcolor = color of your plotted data
tcolor = text color
bcolor = background color
&redraw = flag to redraw graph on fist call only
*/


void Graph(Adafruit_SharpMem &d, double x, double y, double gx, double gy, double w, double h, double xlo, double xhi, double xinc, double ylo, double yhi, double yinc, String title, String xlabel, String ylabel, unsigned int gcolor, unsigned int acolor, unsigned int pcolor, unsigned int tcolor, unsigned int bcolor, boolean &redraw) {

	static double ox, oy;
	double ydiv, xdiv;
	// note my transform function is the same as the map function, except the map uses long and we need doubles
	double i;
	double temp;
	int rot, newrot;

	if (redraw == true) {

		redraw = false;
		ox = (x - xlo) * ( w) / (xhi - xlo) + gx;
		oy = (y - ylo) * (gy - h - gy) / (yhi - ylo) + gy;
		// draw y scale
		for ( i = ylo; i <= yhi; i += yinc) {
			// compute the transform
			temp =  (i - ylo) * (gy - h - gy) / (yhi - ylo) + gy;

			if (i == 0) {
				d.drawLine(gx, temp, gx + w, temp, acolor);
			}
			else {
				d.drawLine(gx, temp, gx + w, temp, gcolor);
			}

			d.setTextSize(1);
			d.setTextColor(tcolor, bcolor);
			d.setCursor(gx - 40, temp);
			// precision is default Arduino--this could really use some format control
			d.println(i);
		}
		// draw x scale
		for (i = xlo; i <= xhi; i += xinc) {

			// compute the transform

			temp =  (i - xlo) * ( w) / (xhi - xlo) + gx;
			if (i == 0) {
				d.drawLine(temp, gy, temp, gy - h, acolor);
			}
			else {
				d.drawLine(temp, gy, temp, gy - h, gcolor);
			}

			d.setTextSize(1);
			d.setTextColor(tcolor, bcolor);
			d.setCursor(temp, gy + 10);
			// precision is default Arduino--this could really use some format control
			d.println(i);
		}

		//now draw the labels
		d.setTextSize(2);
		d.setTextColor(tcolor, bcolor);
		d.setCursor(gx , gy - h - 30);
		d.println(title);

		d.setTextSize(1);
		d.setTextColor(acolor, bcolor);
		d.setCursor(gx , gy + 20);
		d.println(xlabel);

		d.setTextSize(1);
		d.setTextColor(acolor, bcolor);
		d.setCursor(gx - 30, gy - h - 10);
		d.println(ylabel);
	}

	// graph drawn now plot the data
	// the entire plotting code are these few lines...
	// recall that ox and oy are initialized as static above
	x =  (x - xlo) * ( w) / (xhi - xlo) + gx;
	y =  (y - ylo) * (gy - h - gy) / (yhi - ylo) + gy;
	d.drawLine(ox, oy, x, y, pcolor);
	d.drawLine(ox, oy + 1, x, y + 1, pcolor);
	d.drawLine(ox, oy - 1, x, y - 1, pcolor);
	ox = x;
	oy = y;

}

/*
End of graphing function
*/

Thanks for code, your display is much bigger than one I’m using , my is only 128x128!

@daki, I have that one as well. I also have the color 128x128 that @RWB sent me so I could write a library for it. :wink:

@peekay123 One I have is color TFT based on the ST7735S and I have GFX library ported and working, once I get temperature reading and data logging working I will check how temperature graph will look on the small display!