master eccb26ce4ff3 cached
4 files
12.0 KB
3.4k tokens
1 requests
Download .txt
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)

[![MIT License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![GitHub stars](https://img.shields.io/github/stars/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-)](https://github.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/stargazers)
[![YouTube](https://img.shields.io/badge/YouTube-Video-red?logo=youtube)](https://youtu.be/K28Az3-gV7E)

![ESP32](https://img.shields.io/badge/ESP32-Supported-green?logo=espressif)
![Arduino](https://img.shields.io/badge/Arduino-Compatible-00979D?logo=arduino)
![Radiation](https://img.shields.io/badge/CPM-Counts%20Per%20Minute-orange)

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;  
//    }
    
    
  }
}
  
  
  
Download .txt
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[![MIT License](https://img.shields.io/badge/License-MIT-yellow.svg)](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.

Copied to clipboard!