├── .gitignore ├── LICENSE ├── README.md ├── esp8266-geigercounter.ino ├── images ├── img-1.jpg ├── img-2.jpg ├── img-3.jpg └── schematic.png └── settings.h.example /.gitignore: -------------------------------------------------------------------------------- 1 | settings.h 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Christopher Schirner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mightyohm.com Geigercounter connected to ESP8266 2 | 3 | ❗ **This project assumes that you know how to solder, flash an arduino and use MQTT. This repository is not a tutorial - there are plenty of them around the internet. This repository serves the purpose to provide the code to anyone who wants to use it, or extend it yourself to your needs** ❗ 4 | 5 | ## getting started 6 | 7 | To compile this code, just clone or download the master branch as a zip and ramp up your arduino IDE. 8 | 9 | * Needed external dependencies are PubSubClient and optionally ArduinoOTA. 10 | * Rename `settings.h.example` to `settings.h` 11 | * Change the configuration in settings.h to your needs 12 | * Select Wemos D1 Mini clone in Platform 13 | 14 | 15 | ## how to connect the wires 16 | Here's some code and schematic to connect your mightyohm.com geiger counter to the Internet of Things (IoT). 17 | 18 | ![Schematic](https://raw.githubusercontent.com/schinken/esp8266-geigercounter/master/images/schematic.png "How to connect") 19 | 20 | *You can optionally connect PULSE to D2 of the Wemos D1 and enable PIN_PULSE to receive a mqtt event each count!* 21 | 22 | ## images 23 | 24 |

25 | 26 | 27 | 28 |

29 | 30 | ## license and credits 31 | 32 | This code is under MIT license (Christopher Schirner ) 33 | 34 | 35 | -------------------------------------------------------------------------------- /esp8266-geigercounter.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "settings.h" 5 | 6 | #ifdef OTA_PASSWORD 7 | #include 8 | #endif 9 | 10 | WiFiClient wifiClient; 11 | PubSubClient mqttClient; 12 | SoftwareSerial geigerCounterSerial(PIN_UART_RX, PIN_UART_TX); 13 | 14 | uint8_t idx = 0; 15 | char buffer[64]; 16 | char hostname[24]; 17 | 18 | int lastCPM = 0, currentCPM = 0; 19 | float lastuSv = 0, currentuSv = 0; 20 | unsigned long lastPublishMs = 0; 21 | 22 | void setup() { 23 | // power up wait 24 | delay(3000); 25 | 26 | Serial.begin(115200); 27 | geigerCounterSerial.begin(9600); 28 | delay(10); 29 | 30 | #ifdef WIFI_HOSTNAME 31 | strncpy(hostname, WIFI_HOSTNAME, sizeof(hostname)); 32 | #else 33 | snprintf(hostname, sizeof(hostname), "ESP-GEIGER-%X", ESP.getChipId()); 34 | #endif 35 | 36 | WiFi.hostname(hostname); 37 | WiFi.mode(WIFI_STA); 38 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 39 | 40 | while (WiFi.status() != WL_CONNECTED) { 41 | Serial.print("."); 42 | delay(500); 43 | } 44 | 45 | mqttClient.setClient(wifiClient); 46 | mqttClient.setServer(MQTT_HOST, 1883); 47 | connectMqtt(); 48 | 49 | #ifdef OTA_PASSWORD 50 | ArduinoOTA.setHostname(hostname); 51 | ArduinoOTA.setPassword(OTA_PASSWORD); 52 | ArduinoOTA.begin(); 53 | #endif 54 | 55 | #ifdef PIN_PULSE 56 | pinMode(PIN_PULSE, INPUT); 57 | attachInterrupt(PIN_PULSE, onPulse, RISING); 58 | #endif 59 | } 60 | 61 | #ifdef PIN_PULSE 62 | ICACHE_RAM_ATTR void onPulse() { 63 | mqttClient.publish(MQTT_TOPIC_PULSE, "true"); 64 | } 65 | #endif 66 | 67 | void publishValues() { 68 | char tmp[8]; 69 | 70 | if (currentCPM != lastCPM) { 71 | sprintf(tmp, "%d", currentCPM); 72 | mqttClient.publish(MQTT_TOPIC_CPM, tmp, true); 73 | } 74 | 75 | if (currentuSv != lastuSv) { 76 | sprintf(tmp, "%.2f", currentuSv); 77 | mqttClient.publish(MQTT_TOPIC_USV, tmp, true); 78 | } 79 | 80 | lastCPM = currentCPM; 81 | lastuSv = currentuSv; 82 | } 83 | 84 | void connectMqtt() { 85 | 86 | while (!mqttClient.connected()) { 87 | if (mqttClient.connect(hostname, MQTT_TOPIC_LAST_WILL, 1, true, "disconnected")) { 88 | mqttClient.publish(MQTT_TOPIC_LAST_WILL, "connected", true); 89 | Serial.println("MQTT connected"); 90 | } else { 91 | Serial.println("MQTT connect failed"); 92 | delay(1000); 93 | } 94 | } 95 | 96 | } 97 | 98 | void parseReceivedLine(char* input) { 99 | char segment = 0; 100 | char *token; 101 | 102 | float uSv = 0; 103 | float cpm = 0; 104 | 105 | token = strtok(input, ", "); 106 | 107 | while (token != NULL) { 108 | 109 | switch (segment) { 110 | 111 | // This is just for validation 112 | case IDX_CPS_KEY: if (strcmp(token, "CPS") != 0) return; break; 113 | case IDX_CPM_KEY: if (strcmp(token, "CPM") != 0) return; break; 114 | case IDX_uSv_KEY: if (strcmp(token, "uSv/hr") != 0) return; break; 115 | 116 | case IDX_CPM: 117 | Serial.printf("Current CPM: %s\n", token); 118 | cpm = atoi(token); 119 | break; 120 | 121 | case IDX_uSv: 122 | Serial.printf("Current uSv/hr: %s\n", token); 123 | uSv = atof(token); 124 | break; 125 | } 126 | 127 | if (segment > 7) { 128 | // Invalid! There should be no more than 7 segments 129 | return; 130 | } 131 | 132 | token = strtok(NULL, ", "); 133 | segment++; 134 | } 135 | 136 | currentuSv = uSv; 137 | currentCPM = cpm; 138 | } 139 | 140 | void loop() { 141 | 142 | connectMqtt(); 143 | mqttClient.loop(); 144 | 145 | if (millis() - lastPublishMs > MQTT_PUBLISH_INTERVAL_MS) { 146 | lastPublishMs = millis(); 147 | publishValues(); 148 | } 149 | 150 | if (geigerCounterSerial.available()) { 151 | char input = geigerCounterSerial.read(); 152 | buffer[idx++] = input; 153 | 154 | // Echo Serial-Data from GeigerCounter to USB-Debug 155 | Serial.write(input); 156 | 157 | if (input == '\n') { 158 | parseReceivedLine(buffer); 159 | idx = 0; 160 | } 161 | 162 | // Just in case the buffer gets to big, start from scratch 163 | if (idx > 42) { 164 | idx = 0; 165 | } 166 | 167 | } 168 | 169 | #ifdef OTA_PASSWORD 170 | ArduinoOTA.handle(); 171 | #endif 172 | } 173 | -------------------------------------------------------------------------------- /images/img-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schinken/esp8266-geigercounter/880553b916a3135fb2b2bcc1f7ade2fdb0be9ea4/images/img-1.jpg -------------------------------------------------------------------------------- /images/img-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schinken/esp8266-geigercounter/880553b916a3135fb2b2bcc1f7ade2fdb0be9ea4/images/img-2.jpg -------------------------------------------------------------------------------- /images/img-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schinken/esp8266-geigercounter/880553b916a3135fb2b2bcc1f7ade2fdb0be9ea4/images/img-3.jpg -------------------------------------------------------------------------------- /images/schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/schinken/esp8266-geigercounter/880553b916a3135fb2b2bcc1f7ade2fdb0be9ea4/images/schematic.png -------------------------------------------------------------------------------- /settings.h.example: -------------------------------------------------------------------------------- 1 | #define IDX_CPS_KEY 0 2 | #define IDX_CPM_KEY 2 3 | #define IDX_uSv_KEY 4 4 | 5 | #define IDX_CPM 3 6 | #define IDX_uSv 5 7 | #define IDX_MODE 6 8 | 9 | #define PIN_UART_RX D1 // 4 10 | #define PIN_UART_TX 13 // UNUSED 11 | //#define PIN_PULSE D2 12 | 13 | #define BAUD_GEIGERCOUNTER 9600 14 | 15 | //#define WIFI_HOSTNAME "ESP-GeigerCounter"; 16 | #define WIFI_SSID "xxxx" 17 | #define WIFI_PASSWORD "xxxxx" 18 | 19 | //#define OTA_PASSWORD "foobar" 20 | 21 | #define MQTT_HOST "mqtt.xxxxxxxxx.org" 22 | 23 | #define MQTT_TOPIC_CPM "sensor/geigercounter/cpm" 24 | #define MQTT_TOPIC_USV "sensor/geigercounter/uSv" 25 | #define MQTT_TOPIC_LAST_WILL "sensor/geigercounter/status" 26 | #define MQTT_TOPIC_PULSE "sensor/geigercounter/pulse" 27 | 28 | // Only publishes values if changed since last publish 29 | #define MQTT_PUBLISH_INTERVAL_MS (10 * 1000) --------------------------------------------------------------------------------