-
-
Save antonwinter/be1849c1a4548b21a32d0b3ada01f33e to your computer and use it in GitHub Desktop.
MightyOhm Geiger Counter Wi-Fi and OLED Upgrade Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example Program for MightyOhm Geiger Counter FeatherWing + OLED Upgrade | |
// This example is specifically for use with Adafruit Feather HUZZAH (ESP8266) | |
// It will also work with other Feather boards with modifications | |
// | |
// By: Dan Watson | |
// syncchannel.blogspot.com | |
// 1/31/2016 | |
// This program makes use of the EspSoftSerial library to receive data from the Geiger counter. | |
// EspSoftwareSerial: https://github.com/scottwday/EspSoftSerial | |
// Thank you scottwday for this useful library! | |
// The Adafruit MQTT, MQTT_Client, GFX, and SSD1306 libraries are also used. Official documentation: | |
// https://learn.adafruit.com/adafruit-feather-huzzah-esp8266/overview | |
// https://learn.adafruit.com/adafruit-io/mqtt-api | |
// https://learn.adafruit.com/monochrome-oled-breakouts | |
// All of the MQTT code below is borrowed from Adafruit's example programs. Thank you! | |
#include <SPI.h> | |
#include <Wire.h> | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_SSD1306.h> | |
#include <CircularBuffer.h> | |
#include <EspSoftSerialRx.h> | |
#include <ESP8266WiFi.h> | |
#include "Adafruit_MQTT.h" | |
#include "Adafruit_MQTT_Client.h" | |
#define WLAN_SSID "your ssid here" | |
#define WLAN_PASS "your password here" | |
#define AIO_SERVER "io.adafruit.com" | |
#define AIO_SERVERPORT 1883 | |
#define AIO_USERNAME "your Adafruit IO user name here" | |
#define AIO_KEY "your Adafruit IO private key here" | |
/************ Global State (you don't need to change this!) ******************/ | |
// Create an ESP8266 WiFiClient class to connect to the MQTT server. | |
WiFiClient client; | |
// Store the MQTT server, username, and password in flash memory. | |
// This is required for using the Adafruit MQTT library. | |
const char MQTT_SERVER[] PROGMEM = AIO_SERVER; | |
const char MQTT_USERNAME[] PROGMEM = AIO_USERNAME; | |
const char MQTT_PASSWORD[] PROGMEM = AIO_KEY; | |
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. | |
Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD); | |
/****************************** Feeds ***************************************/ | |
// Modify these feed names to match what you created on Adafruit IO | |
const char CPS_FEED[] PROGMEM = AIO_USERNAME "/feeds/GeigerCPS"; | |
Adafruit_MQTT_Publish cpsfeed = Adafruit_MQTT_Publish(&mqtt, CPS_FEED); | |
const char CPM_FEED[] PROGMEM = AIO_USERNAME "/feeds/GeigerCPM"; | |
Adafruit_MQTT_Publish cpmfeed = Adafruit_MQTT_Publish(&mqtt, CPM_FEED); | |
const char SIEVERTS_FEED[] PROGMEM = AIO_USERNAME "/feeds/GeigerSieverts"; | |
Adafruit_MQTT_Publish sievertsfeed = Adafruit_MQTT_Publish(&mqtt, SIEVERTS_FEED); | |
/****************************************************************************/ | |
#define buttonA 0 | |
#define buttonB 16 | |
#define buttonC 2 | |
#define rxPin 13 | |
Adafruit_SSD1306 display; | |
EspSoftSerialRx SerialGeiger; | |
#if (SSD1306_LCDHEIGHT != 32) | |
#error("Height incorrect, please fix Adafruit_SSD1306.h!"); | |
#endif | |
// Used to store strings arriving from geiger counter | |
String geigerSerial; | |
// Storage for stats | |
int cps = 0; | |
int cpm = 0; | |
float sieverts = 0; | |
// Misc variables for mode and monitoring | |
uint8_t mode = 1; | |
unsigned long geigerTimeout = 0; | |
bool geigerConnected = false; | |
uint8_t publishCounter = 0; | |
bool publishStatus = false; | |
void setup() | |
{ | |
// String from geiger counter will be echoed on USB Serial | |
// Software serial Rx-only is used to receive the string from the geiger counter | |
Serial.begin(9600); | |
SerialGeiger.begin(9600, rxPin); | |
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); | |
// All three buttons on the OLED FeatherWing are used in this example | |
pinMode(buttonA, INPUT_PULLUP); | |
pinMode(buttonC, INPUT_PULLUP); | |
pinMode(buttonC, INPUT_PULLUP); | |
display.clearDisplay(); | |
// Connect to WiFi access point. | |
Serial.println(); Serial.println(); | |
Serial.print("Connecting to "); | |
Serial.println(WLAN_SSID); | |
WiFi.begin(WLAN_SSID, WLAN_PASS); | |
while (WiFi.status() != WL_CONNECTED) { | |
delay(500); | |
Serial.print("."); | |
} | |
Serial.println(); | |
Serial.println("WiFi connected"); | |
Serial.println("IP address: "); Serial.println(WiFi.localIP()); | |
} | |
void loop() | |
{ | |
// Check if a button is pressed and change mode accordingly | |
bool gotButton = false; | |
if (!digitalRead(buttonA)) | |
{ | |
mode = 1; | |
gotButton = true; | |
} | |
else if (!digitalRead(buttonB)) | |
{ | |
mode = 2; | |
gotButton = true; | |
} | |
else if (!digitalRead(buttonC)) | |
{ | |
mode = 3; | |
gotButton = true; | |
} | |
if (gotButton) | |
delay(50); // Debounce | |
// End of button checking | |
// Monitor the serial connection from the geiger counter. | |
// If it is absent for > 3 seconds, display a warning to the user | |
if (millis() > (geigerTimeout + 3000) && geigerConnected == true) | |
{ | |
geigerConnected = false; | |
display.setTextColor(WHITE); | |
display.clearDisplay(); | |
display.setTextSize(1); | |
display.setCursor(0,8); | |
display.println("GEIGER COUNTER"); | |
display.println("NOT CONNECTED!"); | |
display.display(); | |
} | |
// End of serial connection monitoring | |
// Attempt to receive a serial character from the geiger counter | |
// If we got one, append it to the string | |
// If we got a new line character, parse the string and update the display | |
// The strings arrive about once a second, so this loop is also used for timing of publish events | |
unsigned char b; | |
if(SerialGeiger.read(b)) | |
{ | |
geigerSerial += char(b); | |
if (b == 0x0A) // New line, end of string. We need to parse. | |
{ | |
Serial.print(geigerSerial); // Echo the string to USB serial for potential PC monitoring | |
geigerConnected = true; // Record that serial connection health is ok | |
geigerTimeout = millis(); | |
publishCounter++; // When this gets to five (five seconds passed) we will publish | |
SerialGeiger.service(); // Periodic service routine required for this library | |
// Parse CPS, CPM, and uS/hr from the string | |
int comma1Index = geigerSerial.indexOf(','); | |
int comma2Index = geigerSerial.indexOf(',', comma1Index + 1); | |
int comma3Index = geigerSerial.indexOf(',', comma2Index + 1); | |
int comma4Index = geigerSerial.indexOf(',', comma3Index + 1); | |
int comma5Index = geigerSerial.indexOf(',', comma4Index + 1); | |
int comma6Index = geigerSerial.indexOf(',', comma5Index + 1); | |
String cpsString = geigerSerial.substring(comma1Index+1,comma2Index); | |
String cpmString = geigerSerial.substring(comma3Index+1,comma4Index); | |
String sievertsString = geigerSerial.substring(comma5Index+1,comma6Index); | |
cps = cpsString.toInt(); | |
cpm = cpmString.toInt(); | |
sieverts = sievertsString.toFloat(); | |
geigerSerial = ""; // Clear the string for next time | |
// Update the display depending on what mode we are in | |
// Lots of potential to modify/improve this. You could do cool stuff like graphing! | |
switch (mode) { | |
case 1: // Stats | |
display.setTextColor(WHITE); | |
display.setTextSize(1); | |
display.clearDisplay(); | |
display.setCursor(4,8); | |
display.print("CPS:"); | |
display.print(cps); | |
display.print(" | CPM:"); | |
display.print(cpm); | |
display.setCursor(4,20); | |
display.print("uSv/hr: "); | |
display.println(sieverts); | |
display.display(); | |
break; | |
case 2: // CPM only in large text for greater visibility | |
display.setTextColor(WHITE); | |
display.clearDisplay(); | |
display.setTextSize(1); | |
display.setCursor(2,19); | |
display.print("CPM:"); | |
display.setTextSize(3); | |
display.setCursor(30,4); | |
display.print(cpm); | |
display.display(); | |
break; | |
case 3: // Status of Wi-Fi, publishing, and IP address | |
display.setTextSize(1); | |
display.setTextColor(WHITE); | |
display.clearDisplay(); | |
display.setCursor(2,8); | |
display.print("Wi-FI: "); | |
if (WiFi.status() != WL_CONNECTED) | |
display.println("Not Connected"); | |
else if (!publishStatus) | |
display.println("Can't Publish"); | |
else | |
display.println("Connected"); | |
display.setCursor(2,20); | |
display.print("IP: "); | |
display.println(WiFi.localIP()); | |
display.display(); | |
break; | |
} | |
} | |
} | |
MQTT_connect(); | |
// We publish every five seconds to Adafruit IO | |
// If any publish attempt fails, the user will be notified on the Mode 3 screen | |
if (publishCounter >= 5) | |
{ | |
publishCounter = 0; | |
bool publishResults = true; | |
if (!cpsfeed.publish(cps)) | |
publishResults = false; | |
delay(10); | |
if (!cpmfeed.publish(cpm)) | |
publishResults = false; | |
delay(10); | |
if (!sievertsfeed.publish(sieverts)) | |
publishResults = false; | |
publishStatus = publishResults; | |
} | |
} | |
// Function to connect and reconnect as necessary to the MQTT server. | |
// Should be called in the loop function and it will take care if connecting. | |
void MQTT_connect() { | |
int8_t ret; | |
// Stop if already connected. | |
if (mqtt.connected()) { | |
return; | |
} | |
Serial.print("Connecting to MQTT... "); | |
while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected | |
Serial.println(mqtt.connectErrorString(ret)); | |
Serial.println("Retrying MQTT connection in 5 seconds..."); | |
mqtt.disconnect(); | |
delay(5000); // wait 5 seconds | |
} | |
Serial.println("MQTT Connected!"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment