├── .gitattributes ├── En_Calibration_GMv1.1.pdf ├── Geiger Counter Diagram.pdf ├── How to check the system works.pdf ├── Sch__Geiger Counter Kit-v1.1.pdf ├── M4011 Geiger Tube Specification.pdf ├── DIY Geiger Counter Kit-v1.0-no sch.zip ├── How to convert the conuters from Geiger Counter Kit.pdf ├── README.md ├── simpletest └── Geiger_Counter └── Geiger_Counter.ino /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /En_Calibration_GMv1.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/master/En_Calibration_GMv1.1.pdf -------------------------------------------------------------------------------- /Geiger Counter Diagram.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/master/Geiger Counter Diagram.pdf -------------------------------------------------------------------------------- /How to check the system works.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/master/How to check the system works.pdf -------------------------------------------------------------------------------- /Sch__Geiger Counter Kit-v1.1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/master/Sch__Geiger Counter Kit-v1.1.pdf -------------------------------------------------------------------------------- /M4011 Geiger Tube Specification.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/master/M4011 Geiger Tube Specification.pdf -------------------------------------------------------------------------------- /DIY Geiger Counter Kit-v1.0-no sch.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/master/DIY Geiger Counter Kit-v1.0-no sch.zip -------------------------------------------------------------------------------- /How to convert the conuters from Geiger Counter Kit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SensorsIot/Geiger-Counter-RadiationD-v1.1-CAJOE-/master/How to convert the conuters from Geiger Counter Kit.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Geiger Counter (RadiationD-v1.1 CAJOE) 2 | 3 | [![MIT License](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![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) 5 | [![YouTube](https://img.shields.io/badge/YouTube-Video-red?logo=youtube)](https://youtu.be/K28Az3-gV7E) 6 | 7 | ![ESP32](https://img.shields.io/badge/ESP32-Supported-green?logo=espressif) 8 | ![Arduino](https://img.shields.io/badge/Arduino-Compatible-00979D?logo=arduino) 9 | ![Radiation](https://img.shields.io/badge/CPM-Counts%20Per%20Minute-orange) 10 | 11 | Interface with the RadiationD-v1.1 (CAJOE) Geiger counter board. Displays readings on OLED, sends data to ThingSpeak, and triggers IFTTT alerts. 12 | 13 | 📺 **Video Tutorial:** https://youtu.be/K28Az3-gV7E 14 | 15 | ## 🔌 Wiring 16 | 17 | | Function | GPIO | 18 | |----------|------| 19 | | Geiger Counter Output | GPIO 26 | 20 | | OLED SDA | GPIO 5 | 21 | | OLED SCL | GPIO 4 | 22 | 23 | ## 📦 Dependencies 24 | 25 | Install using the Arduino Library Manager: 26 | 27 | | Library | Description | 28 | |---------|-------------| 29 | | [ThingPulse SSD1306](https://github.com/ThingPulse/esp8266-oled-ssd1306) | OLED display driver | 30 | | [IFTTTWebhook](https://github.com/romkey/IFTTTWebhook) | IFTTT notifications | 31 | | [ThingSpeak](https://github.com/mathworks/thingspeak-arduino) | ThingSpeak API | 32 | 33 | ## ⚙️ Configuration 34 | 35 | Edit the credentials in `Geiger_Counter.ino`: 36 | 37 | ```cpp 38 | // WiFi 39 | #define mySSID "your-wifi-name" 40 | #define myPASSWORD "your-wifi-password" 41 | 42 | // IFTTT 43 | #define IFTTT_KEY "your-ifttt-key" 44 | 45 | // ThingSpeak 46 | #define SECRET_CH_ID 0000000 // Your channel number 47 | #define SECRET_WRITE_APIKEY "xxx" // Your API key 48 | ``` 49 | 50 | ### ⏱️ Timing Settings 51 | 52 | ```cpp 53 | #define PERIOD_LOG 15 // Display update interval (seconds) 54 | #define PERIOD_THINKSPEAK 3600 // ThingSpeak upload interval (seconds) 55 | ``` 56 | 57 | ## 📊 Output 58 | 59 | - **Display:** CPM (Counts Per Minute) 60 | - **ThingSpeak:** CPH (Counts Per Hour) 61 | - **IFTTT Alert:** Triggered when CPM ≥ 200 62 | 63 | -------------------------------------------------------------------------------- /simpletest: -------------------------------------------------------------------------------- 1 | /* 2 | edited by genewitch to actually provide clicks per minute on the serial port 3 | in a sane fashion. the original file i forked from just set CPM to 105 and 4 | didn't really work anyhow, as the count was reset every 20 seconds. 5 | There's an issue with my understanding of the way variables work, so please 6 | feel free to fix my cludge with the clock1 and start variables. when they 7 | were in the loop the "minutes" never changed. 8 | 9 | trying to create PR 10 | */ 11 | 12 | /* 13 | Geiger.ino 14 | 15 | This code interacts with the Alibaba RadiationD-v1.1 (CAJOE) Geiger counter board 16 | and reports readings in CPM (Counts Per Minute). 17 | 18 | Author: Andreas Spiess 19 | 20 | Based on initial work of Mark A. Heckler (@MkHeck, mark.heckler@gmail.com) 21 | 22 | License: MIT License 23 | 24 | Please use freely with attribution. Thank you! 25 | */ 26 | 27 | volatile unsigned long counts = 0; // Tube events 28 | unsigned long cpm = 0; // CPM 29 | unsigned long previousMillis; // Time measurement 30 | const int inputPin = 7; // geiger is on this pin? 31 | unsigned int thirds = 0; 32 | unsigned long minutes = 1; 33 | unsigned long start = 0; 34 | 35 | #define LOG_PERIOD 20000 //Logging period in milliseconds 36 | #define MINUTE_PERIOD 60000 37 | 38 | void ISR_impulse() { // Captures count of events from Geiger counter board 39 | counts++; 40 | } 41 | 42 | void setup() { 43 | // put your setup code here, to run once: 44 | Serial.begin(9600); 45 | delay(1000); 46 | Serial.println("Booting..."); 47 | Serial.println("Measuring"); 48 | pinMode(inputPin, INPUT); // Set pin for capturing Tube events 49 | interrupts(); // Enable interrupts 50 | attachInterrupt(digitalPinToInterrupt(inputPin), ISR_impulse, FALLING); // Define interrupt on falling edge 51 | unsigned long clock1 = millis(); 52 | start = clock1; 53 | } 54 | 55 | void loop() { 56 | // put your main code here, to run repeatedly: 57 | unsigned long currentMillis = millis(); 58 | 59 | 60 | 61 | if (currentMillis - previousMillis > LOG_PERIOD) { 62 | 63 | previousMillis = currentMillis; 64 | // Serial.print("previousMillis: "); 65 | // Serial.println(String(previousMillis)); 66 | minutes = (previousMillis - start) / MINUTE_PERIOD; 67 | if (minutes < 1) { 68 | minutes = 1; 69 | } 70 | // Serial.print("minutes: "); 71 | // Serial.println(String(minutes)); 72 | 73 | //cpm = counts * MINUTE_PERIOD / LOG_PERIOD; this is just counts times 3 so: 74 | 75 | cpm = counts / minutes; 76 | Serial.print("Total clicks since start: "); 77 | Serial.println(String(counts)); 78 | Serial.print("Rolling CPM: "); 79 | Serial.println(String(cpm)); 80 | 81 | // if ( thirds > 2) { 82 | // counts = 0; 83 | // thirds = 0; 84 | // } 85 | 86 | 87 | } 88 | } 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Geiger_Counter/Geiger_Counter.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Geiger.ino 3 | 4 | This code interacts with the Alibaba RadiationD-v1.1 (CAJOE) Geiger counter board 5 | and reports on Display readings in CPM (Counts Per Minute). 6 | To the Thingspeak CPH (Counts Per Hour) are reported 7 | Connect the output of the Geiger counter to pin inputPin. 8 | 9 | Install Thingspulse SSD1306 Library IFTTTWebhook and ThingSpeak 10 | Please notice you need to udate the https cerificatet signere certificate within IFTTTWebhook - doues not work with certificate manager. 11 | IFTTTWebhook does not work with parameter .…… i asume as results from api changes. 12 | Examle of my deice https://thingspeak.com/channels/1754536# 13 | 14 | Author Hans Carlos Hofmann 15 | Based on Andreas Spiess 16 | Based on initial work of Mark A. Heckler (@MkHeck, mark.heckler@gmail.com) 17 | License: MIT License 18 | Please use freely with attribution. Thank you! 19 | */ 20 | 21 | #define Version "V1.3.1" 22 | #define CONS 23 | #define WIFI 24 | #define IFTT 25 | #ifdef CONS 26 | #define PRINT_DEBUG_MESSAGES 27 | #endif 28 | 29 | #ifdef WIFI 30 | #include 31 | #include 32 | #ifdef IFTT 33 | #include "IFTTTWebhook.h" 34 | #endif 35 | #include 36 | #endif 37 | #include 38 | #include 39 | 40 | // #include // or define mySSID and myPASSWORD and THINGSPEAK_API_KEY 41 | 42 | #define WIFI_TIMEOUT_DEF 30 43 | #define PERIOD_LOG 15 //Logging period 44 | #define PERIOD_THINKSPEAK 3600 // in seconds, >60 45 | #define WDT_TIMEOUT 10 46 | 47 | #ifndef CREDENTIALS 48 | // WLAN 49 | #ifdef WIFI 50 | #define mySSID "xxx" 51 | #define myPASSWORD "xxx" 52 | 53 | //IFTT 54 | #ifdef IFTT 55 | #define IFTTT_KEY "xxx" 56 | #endif 57 | 58 | // Thingspeak 59 | #define SECRET_CH_ID 00000000 // replace 0000000 with your channel number 60 | #define SECRET_WRITE_APIKEY "xxx" // replace XYZ with your channel write API Key 61 | 62 | #endif 63 | 64 | // IFTTT 65 | #ifdef IFTT 66 | #define EVENT_NAME "Radioactivity" // Name of your event name, set when you are creating the applet 67 | #endif 68 | #endif 69 | 70 | IPAddress ip; 71 | 72 | #ifdef WIFI 73 | WiFiClient client; 74 | 75 | WiFiClientSecure secure_client; 76 | #endif 77 | 78 | SSD1306 display(0x3c, 5, 4); 79 | 80 | const int inputPin = 26; 81 | 82 | int counts = 0; // Tube events 83 | int counts2 = 0; 84 | int cpm = 0; // CPM 85 | unsigned long lastCountTime; // Time measurement 86 | unsigned long lastEntryThingspeak; 87 | unsigned long startCountTime; // Time measurement 88 | unsigned long startEntryThingspeak; 89 | 90 | #ifdef WIFI 91 | unsigned long myChannelNumber = SECRET_CH_ID; 92 | const char * myWriteAPIKey = SECRET_WRITE_APIKEY; 93 | #endif 94 | 95 | 96 | void IRAM_ATTR ISR_impulse() { // Captures count of events from Geiger counter board 97 | counts++; 98 | counts2++; 99 | } 100 | 101 | 102 | void displayInit() { 103 | display.init(); 104 | display.flipScreenVertically(); 105 | display.setFont(ArialMT_Plain_24); 106 | } 107 | 108 | void displayInt(int dispInt, int x, int y) { 109 | display.setColor(WHITE); 110 | display.setTextAlignment(TEXT_ALIGN_CENTER); 111 | display.drawString(x, y, String(dispInt)); 112 | display.setFont(ArialMT_Plain_24); 113 | display.display(); 114 | } 115 | 116 | void displayString(String dispString, int x, int y) { 117 | display.setColor(WHITE); 118 | display.setTextAlignment(TEXT_ALIGN_CENTER); 119 | display.drawString(x, y, dispString); 120 | display.setFont(ArialMT_Plain_24); 121 | display.display(); 122 | } 123 | 124 | 125 | /****reset***/ 126 | void software_Reset() // Restarts program from beginning but does not reset the peripherals and registers 127 | { 128 | #ifdef CONS 129 | Serial.println("resetting by software"); 130 | #endif 131 | displayString("Myreset", 64, 15); 132 | delay(1000); 133 | esp_restart(); 134 | } 135 | 136 | 137 | void IFTTT(int postValue) { 138 | #ifdef WIFI 139 | #ifdef IFTT 140 | IFTTTWebhook webhook(IFTTT_KEY, EVENT_NAME); 141 | if (!webhook.trigger(String(postValue).c_str())) { 142 | #ifdef CONS 143 | Serial.println("Successfully sent to IFTTT"); 144 | } else 145 | { 146 | Serial.println("IFTTT failed!"); 147 | #endif 148 | } 149 | #endif 150 | #endif 151 | } 152 | 153 | void postThingspeak( int value) { 154 | // Write to ThingSpeak. There are up to 8 fields in a channel, allowing you to store up to 8 different 155 | // pieces of information in a channel. Here, we write to field 1. 156 | #ifdef WIFI 157 | int x = ThingSpeak.writeField(myChannelNumber, 1, value, myWriteAPIKey); 158 | #ifdef CONS 159 | if (x == 200) { 160 | Serial.println("Channel update successful"); 161 | } 162 | else { 163 | Serial.println("Problem updating channel. HTTP error code " + String(x)); 164 | } 165 | #endif 166 | #endif 167 | } 168 | 169 | void printStack() 170 | { 171 | #ifdef CONS 172 | char *SpStart = NULL; 173 | char *StackPtrAtStart = (char *)&SpStart; 174 | UBaseType_t watermarkStart = uxTaskGetStackHighWaterMark(NULL); 175 | char *StackPtrEnd = StackPtrAtStart - watermarkStart; 176 | Serial.printf("=== Stack info === "); 177 | Serial.printf("Free Stack is: %d \r\n", (uint32_t)StackPtrAtStart - (uint32_t)StackPtrEnd); 178 | #endif 179 | } 180 | 181 | void setup() { 182 | esp_task_wdt_init(WDT_TIMEOUT, true); //enable panic so ESP32 restarts 183 | esp_task_wdt_add(NULL); //add current thread to WDT watch 184 | 185 | #ifdef CONS 186 | Serial.begin(115200); 187 | Serial.print("This is ") ; Serial.println(Version) ; 188 | #endif 189 | 190 | if (PERIOD_LOG > PERIOD_THINKSPEAK) { 191 | #ifdef CONS 192 | Serial.println("PERIOD_THINKSPEAK has to be bigger than PERIODE_LOG"); 193 | #endif 194 | while (1); 195 | } 196 | displayInit(); 197 | #ifdef WIFI 198 | ThingSpeak.begin(client); // Initialize ThingSpeak 199 | #endif 200 | displayString("Welcome", 64, 0); 201 | displayString(Version, 64, 30); 202 | printStack(); 203 | #ifdef WIFI 204 | #ifdef CONS 205 | Serial.println("Connecting to Wi-Fi"); 206 | #endif 207 | 208 | WiFi.begin(mySSID, myPASSWORD); 209 | 210 | int wifi_loops = 0; 211 | int wifi_timeout = WIFI_TIMEOUT_DEF; 212 | while (WiFi.status() != WL_CONNECTED) { 213 | wifi_loops++; 214 | #ifdef CONS 215 | Serial.print("."); 216 | #endif 217 | delay(500); 218 | if (wifi_loops > wifi_timeout) software_Reset(); 219 | } 220 | #ifdef CONS 221 | Serial.println(); 222 | Serial.println("Wi-Fi Connected"); 223 | #endif 224 | #endif 225 | display.clear(); 226 | displayString("Measuring", 64, 15); 227 | pinMode(inputPin, INPUT); // Set pin for capturing Tube events 228 | #ifdef CONS 229 | Serial.println("Defined Input Pin"); 230 | #endif 231 | attachInterrupt(digitalPinToInterrupt(inputPin), ISR_impulse, FALLING); // Define interrupt on falling edge 232 | Serial.println("Irq installed"); 233 | 234 | startEntryThingspeak = lastEntryThingspeak = millis(); 235 | startCountTime = lastCountTime = millis(); 236 | #ifdef CONS 237 | Serial.println("Initialized"); 238 | #endif 239 | } 240 | 241 | int active = 0 ; 242 | 243 | void loop() { 244 | esp_task_wdt_reset(); 245 | #ifdef WIFI 246 | if (WiFi.status() != WL_CONNECTED) software_Reset(); 247 | #endif 248 | 249 | if (millis() - lastCountTime > (PERIOD_LOG * 1000)) { 250 | #ifdef CONS 251 | Serial.print("Counts: "); Serial.println(counts); 252 | #endif 253 | cpm = (60000 * counts) / (millis() - startCountTime) ; 254 | counts = 0 ; 255 | startCountTime = millis() ; 256 | lastCountTime += PERIOD_LOG * 1000; 257 | display.clear(); 258 | displayString("Radioactivity", 64, 0); 259 | displayInt(cpm, 64, 30); 260 | if (cpm >= 200) { 261 | if (active) { 262 | active = 0 ; 263 | display.clear(); 264 | displayString("¡¡ALARM!!", 64, 0); 265 | displayInt(cpm, 64, 30); 266 | #ifdef IFTT 267 | IFTTT(cpm); 268 | #endif 269 | } ; 270 | } 271 | else if (cpm < 100) 272 | { 273 | active = 1 ; 274 | } ; 275 | #ifdef CONS 276 | Serial.print("cpm: "); Serial.println(cpm); 277 | #endif 278 | printStack(); 279 | } 280 | 281 | if (millis() - lastEntryThingspeak > (PERIOD_THINKSPEAK * 1000)) { 282 | #ifdef CONS 283 | Serial.print("Counts2: "); Serial.println(counts2); 284 | #endif 285 | int averageCPH = (int)(((float)3600000 * (float)counts2) / (float)(millis() - startEntryThingspeak)); 286 | #ifdef CONS 287 | Serial.print("Average cph: "); Serial.println(averageCPH); 288 | #endif 289 | postThingspeak(averageCPH); 290 | lastEntryThingspeak += PERIOD_THINKSPEAK * 1000; 291 | startEntryThingspeak = millis(); 292 | counts2=0; 293 | } ; 294 | delay(50); 295 | } 296 | --------------------------------------------------------------------------------