Repository: SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-
Branch: master
Commit: eccb26ce4ff3
Files: 4
Total size: 12.0 KB
Directory structure:
gitextract_pe8oe3e5/
├── .gitattributes
├── Geiger_Counter/
│ └── Geiger_Counter.ino
├── README.md
└── simpletest
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
# Auto detect text files and perform LF normalization
* text=auto
================================================
FILE: Geiger_Counter/Geiger_Counter.ino
================================================
/*
Geiger.ino
This code interacts with the Alibaba RadiationD-v1.1 (CAJOE) Geiger counter board
and reports on Display readings in CPM (Counts Per Minute).
To the Thingspeak CPH (Counts Per Hour) are reported
Connect the output of the Geiger counter to pin inputPin.
Install Thingspulse SSD1306 Library IFTTTWebhook and ThingSpeak
Please notice you need to udate the https cerificatet signere certificate within IFTTTWebhook - doues not work with certificate manager.
IFTTTWebhook does not work with parameter .…… i asume as results from api changes.
Examle of my deice https://thingspeak.com/channels/1754536#
Author Hans Carlos Hofmann
Based on Andreas Spiess
Based on initial work of Mark A. Heckler (@MkHeck, mark.heckler@gmail.com)
License: MIT License
Please use freely with attribution. Thank you!
*/
#define Version "V1.3.1"
#define CONS
#define WIFI
#define IFTT
#ifdef CONS
#define PRINT_DEBUG_MESSAGES
#endif
#ifdef WIFI
#include <WiFi.h>
#include <WiFiClientSecure.h>
#ifdef IFTT
#include "IFTTTWebhook.h"
#endif
#include <ThingSpeak.h>
#endif
#include <SSD1306.h>
#include <esp_task_wdt.h>
// #include <credentials.h> // or define mySSID and myPASSWORD and THINGSPEAK_API_KEY
#define WIFI_TIMEOUT_DEF 30
#define PERIOD_LOG 15 //Logging period
#define PERIOD_THINKSPEAK 3600 // in seconds, >60
#define WDT_TIMEOUT 10
#ifndef CREDENTIALS
// WLAN
#ifdef WIFI
#define mySSID "xxx"
#define myPASSWORD "xxx"
//IFTT
#ifdef IFTT
#define IFTTT_KEY "xxx"
#endif
// Thingspeak
#define SECRET_CH_ID 00000000 // replace 0000000 with your channel number
#define SECRET_WRITE_APIKEY "xxx" // replace XYZ with your channel write API Key
#endif
// IFTTT
#ifdef IFTT
#define EVENT_NAME "Radioactivity" // Name of your event name, set when you are creating the applet
#endif
#endif
IPAddress ip;
#ifdef WIFI
WiFiClient client;
WiFiClientSecure secure_client;
#endif
SSD1306 display(0x3c, 5, 4);
const int inputPin = 26;
int counts = 0; // Tube events
int counts2 = 0;
int cpm = 0; // CPM
unsigned long lastCountTime; // Time measurement
unsigned long lastEntryThingspeak;
unsigned long startCountTime; // Time measurement
unsigned long startEntryThingspeak;
#ifdef WIFI
unsigned long myChannelNumber = SECRET_CH_ID;
const char * myWriteAPIKey = SECRET_WRITE_APIKEY;
#endif
void IRAM_ATTR ISR_impulse() { // Captures count of events from Geiger counter board
counts++;
counts2++;
}
void displayInit() {
display.init();
display.flipScreenVertically();
display.setFont(ArialMT_Plain_24);
}
void displayInt(int dispInt, int x, int y) {
display.setColor(WHITE);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(x, y, String(dispInt));
display.setFont(ArialMT_Plain_24);
display.display();
}
void displayString(String dispString, int x, int y) {
display.setColor(WHITE);
display.setTextAlignment(TEXT_ALIGN_CENTER);
display.drawString(x, y, dispString);
display.setFont(ArialMT_Plain_24);
display.display();
}
/****reset***/
void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers
{
#ifdef CONS
Serial.println("resetting by software");
#endif
displayString("Myreset", 64, 15);
delay(1000);
esp_restart();
}
void IFTTT(int postValue) {
#ifdef WIFI
#ifdef IFTT
IFTTTWebhook webhook(IFTTT_KEY, EVENT_NAME);
if (!webhook.trigger(String(postValue).c_str())) {
#ifdef CONS
Serial.println("Successfully sent to IFTTT");
} else
{
Serial.println("IFTTT failed!");
#endif
}
#endif
#endif
}
void postThingspeak( int value) {
// Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different
// pieces of information in a channel. Here, we write to field 1.
#ifdef WIFI
int x = ThingSpeak.writeField(myChannelNumber, 1, value, myWriteAPIKey);
#ifdef CONS
if (x == 200) {
Serial.println("Channel update successful");
}
else {
Serial.println("Problem updating channel. HTTP error code " + String(x));
}
#endif
#endif
}
void printStack()
{
#ifdef CONS
char *SpStart = NULL;
char *StackPtrAtStart = (char *)&SpStart;
UBaseType_t watermarkStart = uxTaskGetStackHighWaterMark(NULL);
char *StackPtrEnd = StackPtrAtStart - watermarkStart;
Serial.printf("=== Stack info === ");
Serial.printf("Free Stack is: %d \r\n", (uint32_t)StackPtrAtStart - (uint32_t)StackPtrEnd);
#endif
}
void setup() {
esp_task_wdt_init(WDT_TIMEOUT, true); //enable panic so ESP32 restarts
esp_task_wdt_add(NULL); //add current thread to WDT watch
#ifdef CONS
Serial.begin(115200);
Serial.print("This is ") ; Serial.println(Version) ;
#endif
if (PERIOD_LOG > PERIOD_THINKSPEAK) {
#ifdef CONS
Serial.println("PERIOD_THINKSPEAK has to be bigger than PERIODE_LOG");
#endif
while (1);
}
displayInit();
#ifdef WIFI
ThingSpeak.begin(client); // Initialize ThingSpeak
#endif
displayString("Welcome", 64, 0);
displayString(Version, 64, 30);
printStack();
#ifdef WIFI
#ifdef CONS
Serial.println("Connecting to Wi-Fi");
#endif
WiFi.begin(mySSID, myPASSWORD);
int wifi_loops = 0;
int wifi_timeout = WIFI_TIMEOUT_DEF;
while (WiFi.status() != WL_CONNECTED) {
wifi_loops++;
#ifdef CONS
Serial.print(".");
#endif
delay(500);
if (wifi_loops > wifi_timeout) software_Reset();
}
#ifdef CONS
Serial.println();
Serial.println("Wi-Fi Connected");
#endif
#endif
display.clear();
displayString("Measuring", 64, 15);
pinMode(inputPin, INPUT); // Set pin for capturing Tube events
#ifdef CONS
Serial.println("Defined Input Pin");
#endif
attachInterrupt(digitalPinToInterrupt(inputPin), ISR_impulse, FALLING); // Define interrupt on falling edge
Serial.println("Irq installed");
startEntryThingspeak = lastEntryThingspeak = millis();
startCountTime = lastCountTime = millis();
#ifdef CONS
Serial.println("Initialized");
#endif
}
int active = 0 ;
void loop() {
esp_task_wdt_reset();
#ifdef WIFI
if (WiFi.status() != WL_CONNECTED) software_Reset();
#endif
if (millis() - lastCountTime > (PERIOD_LOG * 1000)) {
#ifdef CONS
Serial.print("Counts: "); Serial.println(counts);
#endif
cpm = (60000 * counts) / (millis() - startCountTime) ;
counts = 0 ;
startCountTime = millis() ;
lastCountTime += PERIOD_LOG * 1000;
display.clear();
displayString("Radioactivity", 64, 0);
displayInt(cpm, 64, 30);
if (cpm >= 200) {
if (active) {
active = 0 ;
display.clear();
displayString("¡¡ALARM!!", 64, 0);
displayInt(cpm, 64, 30);
#ifdef IFTT
IFTTT(cpm);
#endif
} ;
}
else if (cpm < 100)
{
active = 1 ;
} ;
#ifdef CONS
Serial.print("cpm: "); Serial.println(cpm);
#endif
printStack();
}
if (millis() - lastEntryThingspeak > (PERIOD_THINKSPEAK * 1000)) {
#ifdef CONS
Serial.print("Counts2: "); Serial.println(counts2);
#endif
int averageCPH = (int)(((float)3600000 * (float)counts2) / (float)(millis() - startEntryThingspeak));
#ifdef CONS
Serial.print("Average cph: "); Serial.println(averageCPH);
#endif
postThingspeak(averageCPH);
lastEntryThingspeak += PERIOD_THINKSPEAK * 1000;
startEntryThingspeak = millis();
counts2=0;
} ;
delay(50);
}
================================================
FILE: README.md
================================================
# Geiger Counter (RadiationD-v1.1 CAJOE)
[](https://opensource.org/licenses/MIT)
[](https://github.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/stargazers)
[](https://youtu.be/K28Az3-gV7E)



Interface with the RadiationD-v1.1 (CAJOE) Geiger counter board. Displays readings on OLED, sends data to ThingSpeak, and triggers IFTTT alerts.
📺 **Video Tutorial:** https://youtu.be/K28Az3-gV7E
## 🔌 Wiring
| Function | GPIO |
|----------|------|
| Geiger Counter Output | GPIO 26 |
| OLED SDA | GPIO 5 |
| OLED SCL | GPIO 4 |
## 📦 Dependencies
Install using the Arduino Library Manager:
| Library | Description |
|---------|-------------|
| [ThingPulse SSD1306](https://github.com/ThingPulse/esp8266-oled-ssd1306) | OLED display driver |
| [IFTTTWebhook](https://github.com/romkey/IFTTTWebhook) | IFTTT notifications |
| [ThingSpeak](https://github.com/mathworks/thingspeak-arduino) | ThingSpeak API |
## ⚙️ Configuration
Edit the credentials in `Geiger_Counter.ino`:
```cpp
// WiFi
#define mySSID "your-wifi-name"
#define myPASSWORD "your-wifi-password"
// IFTTT
#define IFTTT_KEY "your-ifttt-key"
// ThingSpeak
#define SECRET_CH_ID 0000000 // Your channel number
#define SECRET_WRITE_APIKEY "xxx" // Your API key
```
### ⏱️ Timing Settings
```cpp
#define PERIOD_LOG 15 // Display update interval (seconds)
#define PERIOD_THINKSPEAK 3600 // ThingSpeak upload interval (seconds)
```
## 📊 Output
- **Display:** CPM (Counts Per Minute)
- **ThingSpeak:** CPH (Counts Per Hour)
- **IFTTT Alert:** Triggered when CPM ≥ 200
================================================
FILE: simpletest
================================================
/*
edited by genewitch to actually provide clicks per minute on the serial port
in a sane fashion. the original file i forked from just set CPM to 105 and
didn't really work anyhow, as the count was reset every 20 seconds.
There's an issue with my understanding of the way variables work, so please
feel free to fix my cludge with the clock1 and start variables. when they
were in the loop the "minutes" never changed.
trying to create PR
*/
/*
Geiger.ino
This code interacts with the Alibaba RadiationD-v1.1 (CAJOE) Geiger counter board
and reports readings in CPM (Counts Per Minute).
Author: Andreas Spiess
Based on initial work of Mark A. Heckler (@MkHeck, mark.heckler@gmail.com)
License: MIT License
Please use freely with attribution. Thank you!
*/
volatile unsigned long counts = 0; // Tube events
unsigned long cpm = 0; // CPM
unsigned long previousMillis; // Time measurement
const int inputPin = 7; // geiger is on this pin?
unsigned int thirds = 0;
unsigned long minutes = 1;
unsigned long start = 0;
#define LOG_PERIOD 20000 //Logging period in milliseconds
#define MINUTE_PERIOD 60000
void ISR_impulse() { // Captures count of events from Geiger counter board
counts++;
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
delay(1000);
Serial.println("Booting...");
Serial.println("Measuring");
pinMode(inputPin, INPUT); // Set pin for capturing Tube events
interrupts(); // Enable interrupts
attachInterrupt(digitalPinToInterrupt(inputPin), ISR_impulse, FALLING); // Define interrupt on falling edge
unsigned long clock1 = millis();
start = clock1;
}
void loop() {
// put your main code here, to run repeatedly:
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > LOG_PERIOD) {
previousMillis = currentMillis;
// Serial.print("previousMillis: ");
// Serial.println(String(previousMillis));
minutes = (previousMillis - start) / MINUTE_PERIOD;
if (minutes < 1) {
minutes = 1;
}
// Serial.print("minutes: ");
// Serial.println(String(minutes));
//cpm = counts * MINUTE_PERIOD / LOG_PERIOD; this is just counts times 3 so:
cpm = counts / minutes;
Serial.print("Total clicks since start: ");
Serial.println(String(counts));
Serial.print("Rolling CPM: ");
Serial.println(String(cpm));
// if ( thirds > 2) {
// counts = 0;
// thirds = 0;
// }
}
}
gitextract_pe8oe3e5/ ├── .gitattributes ├── Geiger_Counter/ │ └── Geiger_Counter.ino ├── README.md └── simpletest
Condensed preview — 4 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (13K chars).
[
{
"path": ".gitattributes",
"chars": 65,
"preview": "# Auto detect text files and perform LF normalization\n* text=auto"
},
{
"path": "Geiger_Counter/Geiger_Counter.ino",
"chars": 7449,
"preview": " /*\n Geiger.ino\n\n This code interacts with the Alibaba RadiationD-v1.1 (CAJOE) Geiger counter board\n and reports o"
},
{
"path": "README.md",
"chars": 2032,
"preview": "# Geiger Counter (RadiationD-v1.1 CAJOE)\n\n[](https://"
},
{
"path": "simpletest",
"chars": 2737,
"preview": "/* \n edited by genewitch to actually provide clicks per minute on the serial port\n in a sane fashion. the original f"
}
]
About this extraction
This page contains the full source code of the SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE- GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 4 files (12.0 KB), approximately 3.4k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.