View Single Post
Old 11-07-2017, 11:59 AM   #20
joefarmer
 
joefarmer's Avatar

Name: joefarmer
Title: MR. Supreme Overlord
Status: Not Here
Join Date: Jul 2006
Location: ohio
Member`s Gallery
Posts: 6,137
Latter half for me too. Here's code that shows 4 SPI temp probes and 4 I2C CO2 pressure probes in my beer fridge over an ESP8266 running code spit out of an Arduino IDE. The base was a 4 probe BBQ controller, so the code is terribly messy and shouldn't be used by anyone.

huzzah fridge - ThingSpeak IoT

Code:
#include <Wire.h>
#include <Adafruit_ADS1015.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <WiFiUdp.h>
#include "SimpleTimer.h"              // multiple, polled timer events without using a hardware (AVR) timer, but (much) less precision wrt the interval
#include "MCP320x.h"


#define DebugSerial		Serial
#define DEBUG										// enable BLYNK_PRINT and a corresponding serial output to capture the stream

Adafruit_ADS1015 ads;     /* Use thi for the 12-bit version */

/*
   probe and related thermistor defines
   Probe 1 must be connected to A0 and then sequentially from there
*/
#define PROBE1_TEMP				V0				// THIS GROUP MUST BE SEQUENTIAL
#define PROBE2_TEMP				V1
#define PROBE3_TEMP				V2
#define PROBE4_TEMP				V3

#define PROBE1_SETPT				V4				// THIS GROUP MUST BE SEQUENTIAL
#define PROBE2_SETPT				V5
#define PROBE3_SETPT				V6
#define PROBE4_SETPT				V7

#define	PROBE1_LED				V8
#define	PROBE2_LED				V9
#define	PROBE3_LED				V10
#define	PROBE4_LED				V11

#define	CONNECTED_LED			V12

#define	P1_CONNECTED			V13
#define	P2_CONNECTED			V14
#define	P3_CONNECTED			V15
#define	P4_CONNECTED			V16

#define	CLONE_P1					V17


/* ================================= SPI A to D converter MPC3204 ====================== */


#define	ADC_ZERO_THRESHOLD		10				// threshold value for a zero reading (capacitance?)
#define ADC_SAMPLES        		5				// number of sames to taken when reading analog ports for temp values

MCP320x MCP(SS);								// see pins_arduino.h for ESP8266/Huzzah - using only 1 parameter forces SPI MODE (uses SPI library)

/* ================================= sketch ======================== */

/*
   Steinhart-Hart coefficients obtained empirically from the calibration utility for the Maverik ET-73 200k ohm probe
   See https://en.wikipedia.org/wiki/Steinhart-Hart for reference and readTemp() below
*/
#define	A						0.001433954477
#define B						0.000076877069
#define C						0.000000537597


/*
   other defines
*/
#define	PROBE_COUNT			4				// number of temperature probes 
#define	ADC_RESOLUTION		4095			// ADC resolution: depends on the platform. Mega/Uno is 10 bits, so (2^10)-1 = 1023. This is for the 12-bit MPC3204 SPI ADC



/*
   data associated with each temperature probe
*/
typedef struct {
	uint16_t		Setpoint;					// setpoint
	uint16_t		SavedSetpoint;				// copy to save for a disconnected probe
	uint16_t		CurrentTemp;				// current temperature. 
  float       dCurrentTemp;        // current temperature. 
	uint8_t		SetpointReached :1;		// if set temperature has been reached
	uint8_t		Present         :1;		// true if probe is connected
	uint8_t		TempChanged     :1;		// true if temp has changed - throttles updates to Blynk dashboard
} ProbeType;

ProbeType Probe[PROBE_COUNT];
uint32_t seriesResistor[PROBE_COUNT] = { 197900, 200500, 197800, 198800 };		// Measured series resistor value in ohms. Must be the SAME as the nominal 25deg C resistance of the probe


/* ================================================== Timer functions =========================================================================== */

// stagger the intervals to allow time for the server messages to complete. Also, use primes in case that helps.
#define	SETPT_DELAY			1609			// how often setpoints are checked in msec
#define PROBE_DELAY			1009			// how often probe temperatures are read in msec
#define TEMP_DELAY			1289			// how often dashboard temperature display values are pushed

#define LCD_DELAY				3049			// how often physical LCD is updated (slow enough to minimize flicker)
#define PUSH_DELAY			300000			// how often push notifications for setpoint reached are done in msec


SimpleTimer timer;

/* ==========================================================  GENERAL ================================================================================ */

bool	redrawScreen = false;							// set when a screen redraw is needed
bool	firstConnect = true;							// true after we have connected once


 // ThingSpeak Settings
  char thingSpeakAddress[] = "api.thingspeak.com";
  String writeAPIKey = "yourkeyhere";
  const int updateThingSpeakInterval = 30 * 1000;      // Time interval in milliseconds to update ThingSpeak (number of seconds * 1000 = interval)


void setup ( void ) {

#if defined(DEBUG)
	DebugSerial.begin(9600);
	while ( !DebugSerial );
#endif // DEBUG
	

	MCP.setMCPConfig(MCP_SINGLE, MCP_ALL_PORTS);			// single mode for all MPC3204 pins

	/*
		Program flow:
		
		Event										Handler				Dashboard updated
		-----------------------------   -------------------   ----------------
		Setpoint set in dashboard			BLYNK_WRITE()			YES
		Probe temperature change			updateProbes()
		Probe removed							updateProbes()			(YES)
		Probe re-inserted						updateProbes()			(YES)
		Dashboard Temp display update		updateTemps()			YES
		Setpoint reached						updateSetpoints()
		Dashboard setpt LED updated		updateSetpoints()		YES
		Setpoint push notices				sendPushNotices()
		LCD updated								updateLCD()
	*/

	timer.setInterval(SETPT_DELAY, updateSetpoints);
	timer.setInterval(PROBE_DELAY, updateProbes);
	timer.setInterval(LCD_DELAY, updateLCD);
	timer.setInterval(PUSH_DELAY, updateThingspeak);

 WiFi.mode(WIFI_STA);

   ads.begin();
}

/*
 Check current values to see if probe setpoints have been reached
 Note that for the setpoint flag to be set, it must be present. Thus, we don't need to check this in other functions
 Also updates Blynk dashboard setpoint LEDs
*/
void updateSetpoints ( void ) {
	for ( uint8_t i = 0; i < PROBE_COUNT; i++ ) {
		if ( Probe[i].Present ) {
			if ( (Probe[i].Setpoint > 0) && (Probe[i].CurrentTemp >= Probe[i].Setpoint) ) {
				Probe[i].SetpointReached = true;
			} else {
				Probe[i].SetpointReached = false;
			}
		}
	}
}


/* 
   Derive the resistance of the probe to use in the Steinhart-Hart eqution.
   We can do this given the known value of the series resistor in the fixed part of the voltage divider
   and the fact that since V = I*R the voltage drop on each resistor is directly proportional to voltage.
   Thus, we can use a ratio to determine the resistance of the probe without using the reference voltage which can vary considerably from 5V.
   Also, this allows us to use the same code on 5V or 3.3V platforms :-) as well as just working with the digitized reading without any voltage conversions.
   
   NOTE: both float and double on Arduino are 32-bit values. No difference between the two.
*/
float calcResistance ( const uint8_t pin ) {
	float reading = 0;

	for ( uint8_t i = 0; i < ADC_SAMPLES; i++ ) {
		reading += MCP.readChannel(pin);
	}
	if ( reading >= ((ADC_RESOLUTION * ADC_SAMPLES) - 20)) {
		// probe disconnected
		return 0;
	} else {
		reading /= (float)ADC_SAMPLES;
		reading = (ADC_RESOLUTION / reading) - 1;
		return (seriesResistor[pin] / reading);
	}
}

/*
  get the normalized raw value of the probe on the given pin for debug
  note that a disconnected probe will return 0 
*/
uint16_t probeRaw ( const uint8_t pin ) {
	uint16_t reading = 0;

	for ( uint8_t i = 0; i < ADC_SAMPLES; i++ ) {
		reading += MCP.readChannel(pin);
	}
	reading /= ADC_SAMPLES;
	return reading;
}

/*
   read the temperature from the given analog pin and return temperature in degrees F
   uses the Steinhart-Hart equation
   Note: when using constants in float calculations, make sure there is a decimal point
*/
float readTemp ( const uint8_t pin ) {
	float R, kelvin;

	R = calcResistance(pin);
	if ( R == 0 ) {
		// probe disconnected
		return 0;
	} else {
		kelvin = 1.0/(A + B*log(R) + C*pow(log(R), 3.0));
		return ((kelvin  * (9.0/5.0)) - 459.67);				// K to F conversion
	}
}

/*
  Get current probe temps
  Check for probes that have been disconnected or reconnected
     - update Blynk dashboard if probe status has changed
*/
void updateProbes ( void ) {
	for ( uint8_t i = 0; i < PROBE_COUNT; i++ ) {
		uint16_t temp = (uint16_t)readTemp(i);
      Probe[i].dCurrentTemp = readTemp(i);
		
		// get probe temps & handle disconnects/reconnects
		if ( temp != Probe[i].CurrentTemp ) {
			Probe[i].CurrentTemp = temp;
			Probe[i].TempChanged = true;
		}
		if ( (Probe[i].CurrentTemp == 0) && Probe[i].Present ) {
			/*
			   probe disconnected:
			   push dashboard setpoint slider value
			   temperature will be updated with the next BLYNK_READ of the probe temp
			*/
			Probe[i].Present = false;
			Probe[i].Setpoint = 0;
			Probe[i].SetpointReached = false;
			redrawScreen = true;
		} else  if ( (Probe[i].CurrentTemp > 0) && !Probe[i].Present ) {
			// reinserted - reset to previous setpoint
			Probe[i].Present = true;
			Probe[i].Setpoint = Probe[i].SavedSetpoint;
			redrawScreen = true;
		}
	}
}

/*
 Update the physical LCD display
 This happens even when Blynk is offline
 Periodically display an offline message when Blynk is offline
*/
void updateLCD ( void ) {
	static uint8_t	offlineCount = 0;

	if ( redrawScreen ) {
		redrawScreen = false;
	}
 
  for(int i = 0;i < PROBE_COUNT; i++ )
  {
    DebugSerial.print("field"); 
    DebugSerial.print(i+5);
    DebugSerial.print("=");
    DebugSerial.print(ads.readADC_SingleEnded(i) * 0.0255);
    DebugSerial.println("&"); 
  }
}

int status = WL_IDLE_STATUS;
void updateThingspeak ( void ) {
    if ( status != WL_CONNECTED) { 
      DebugSerial.println("Couldn't get a wifi connection");
      WiFi.printDiag(Serial);
      status = WiFi.begin("SSID", "mypw");
    } 
    else {
      WiFiClient client;
      while(!client.connect("api.thingspeak.com", 80)) {
        DebugSerial.print(".");
      }

      String temps = readTemps();
      
      // Make a HTTP request:
      client.print("POST /update HTTP/1.1\n");
      client.print("Host: api.thingspeak.com\n");
      client.print("Connection: close\n");
      client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n");
      client.print("Content-Type: application/x-www-form-urlencoded\n");
      client.print("Content-Length: ");
      client.print(temps.length());
      client.print("\n\n");
      client.print(temps);
      
      client.stop();
      client.flush();
      DebugSerial.println(temps);
    }
}

String readTemps() 
{ 
  String temp;
  
  for(int i = 0;i < PROBE_COUNT; i++ )
  {
    temp += "field"; 
    temp += (i+1);
    temp += "=";
    temp += Probe[i].dCurrentTemp;
    temp += "&"; 
  }

  for(int i = 0;i < PROBE_COUNT; i++ )
  {
    temp += "field"; 
    temp += (i+5);
    temp += "=";
    temp += ads.readADC_SingleEnded(i) * 0.0255;
    temp += "&"; 
  }
   
  return temp;
}

/*
 LOOP
*/
void loop ( void ) {
	yield();
	timer.run();
}
__________________
brandon'); DROP TABLE Users;--
1948 Dodge 1.5t 12v RH swap | 99 F250 12v RE test rkt | 11 X5 'no soup' | 08 F250 CR RE swap | 05 2500 CR 68 standalone
firepunk.com
  Reply With Quote