├── .get_version.py
├── .gitignore
├── .prepare_release
├── .travis.yml
├── LICENSE
├── README.md
├── circuit.fzz
├── lib
├── HTTP
│ ├── ThermometerWebserver.cpp
│ └── ThermometerWebserver.h
├── Helpers
│ └── IntParsing.h
├── MQTT
│ ├── MqttClient.cpp
│ └── MqttClient.h
├── Settings
│ ├── Settings.cpp
│ └── Settings.h
├── Sha
│ ├── HmacHelpers.cpp
│ ├── HmacHelpers.h
│ ├── sha1.cpp
│ └── sha1.h
├── TempIface
│ ├── TempIface.cpp
│ └── TempIface.h
├── TokenParsing
│ ├── TokenIterator.cpp
│ ├── TokenIterator.h
│ ├── UrlTokenBindings.cpp
│ └── UrlTokenBindings.h
└── WebStrings
│ ├── IndexPage.h
│ ├── Javascript.h
│ └── Stylesheet.h
├── platformio.ini
└── src
└── main.cpp
/.get_version.py:
--------------------------------------------------------------------------------
1 | from subprocess import check_output
2 | import sys
3 | import os
4 | import platform
5 | import subprocess
6 |
7 | dir_path = os.path.dirname(os.path.realpath(__file__))
8 | os.chdir(dir_path)
9 |
10 | # http://stackoverflow.com/questions/11210104/check-if-a-program-exists-from-a-python-script
11 | def is_tool(name):
12 | cmd = "where" if platform.system() == "Windows" else "which"
13 | try:
14 | check_output([cmd, "git"])
15 | return True
16 | except:
17 | return False
18 |
19 | version = "UNKNOWN"
20 |
21 | if is_tool("git"):
22 | try:
23 | version = check_output(["git", "describe", "--always"]).rstrip()
24 | except:
25 | try:
26 | version = check_output(["git", "rev-parse", "--short", "HEAD"]).rstrip()
27 | except:
28 | pass
29 | pass
30 |
31 | sys.stdout.write("-DESP8266_THERMOMETER_VERSION=%s %s" % (version.decode('utf-8'), ' '.join(sys.argv[1:])))
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .pioenvs
2 | .piolibdeps
3 | .pio
4 | .clang_complete
5 | .gcc-flags.json
6 | lib/readme.txt
7 | .vscode
8 |
--------------------------------------------------------------------------------
/.prepare_release:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eo pipefail
4 |
5 | PROJECT_NAME="esp8266_thermometer"
6 |
7 | prepare_log() {
8 | echo "[prepare release] -- $@"
9 | }
10 |
11 | if [ -z "$(git tag -l --points-at HEAD)" ]; then
12 | prepare_log "Skipping non-tagged commit."
13 | exit 0
14 | fi
15 |
16 | VERSION=$(git describe)
17 |
18 | prepare_log "Preparing release for tagged version: $VERSION"
19 |
20 | mkdir -p dist
21 |
22 | if [ -d .pio/build ]; then
23 | firmware_prefix=".pio/build"
24 | else
25 | firmware_prefix=".pioenvs"
26 | fi
27 |
28 | for file in $(ls ${firmware_prefix}/**/firmware.bin); do
29 | env_dir=$(dirname "$file")
30 | env=$(basename "$env_dir")
31 |
32 | cp "$file" "dist/${PROJECT_NAME}_${env}-${VERSION}.bin"
33 | done
34 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - '2.7'
4 | sudo: false
5 | cache:
6 | directories:
7 | - "~/.platformio"
8 | install:
9 | - pip install -U platformio
10 | - platformio lib install
11 | script:
12 | - platformio run
13 | before_deploy:
14 | - "./.prepare_release"
15 | deploy:
16 | provider: releases
17 | prerelease: true
18 | api_key:
19 | secure: cejQW325lhBBvRy8aaW8SkLAB4vZ+0vo1RKAqRZJkJK9a742+WwG5eDipECaX5KgKYy5DkOyvJXPodMKThj1NzOlr6dclsGgE2F1qFQ8+HP8LloGJqAKahErlyxamGaY9AippkR/yf2YFW85EhTM5qhAiPq2bO2ln0Z9SucYz087/8wtnINVgPTrvioOJDB25oh1+OgUJmcMfN43EThJ8VjwVowXqdvRGJQ/VbsS+cBBlZyxxHTVTrMpV4xMVqT5dtFB1Ny8IGSg3myz3Hs89GC00h1jjipXewKVwDMkZUYVfgxaSfkzkm88I0Q9E9p8+GlL2IZQ9ly2KsmKLXynNq60KuiVIuFkI+6V4gajG7gxNFK9efzJ3zfTRsutxckmj3lDjC+vUnMPo2KlLk/Ko/2DCpLFSlrO0x5aq+LrwF+3UNZFFmpvuG/UtyHod5/3UCa2IhRfQUerFFD7mWpSrA3vvZEz+XmWVXx8VkSBN1HIejhN8h+q0goU+lAAywiQppfYk5R+W2p+vXXsenFdw+hwG5zrG0p7pnvvVnXgJl8yyHRMIFin94zsyAM8BaCwNQ7zbEIy8faU24OxofNx4qalf+xs7VkcVYrDOYwtj+Or3ZKrrPVCRnsC4DsfO5g4jeuJDvMaZmk6QB6eif0Bn3u1iE8e0Ygm6L1RxJqw8pc=
20 | file_glob: true
21 | skip_cleanup: true
22 | file: dist/*.bin
23 | on:
24 | repo: sidoh/esp8266_thermometer
25 | tags: true
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Chris Mullins
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 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Thermometer [](https://travis-ci.org/sidoh/esp8266_thermometer) [](https://github.com/sidoh/esp8266_thermometer/releases/latest) [![License][shield-license]][info-license]
2 |
3 | ESP8266-based thermometer. Pushes temperature data to a URL or MQTT at a configurable interval. Suitable for battery power. Works with multiple probes.
4 |
5 | ## Parts
6 |
7 | * ESP8266. I'm using a NodeMCUs.
8 | * DS18B20 temperature probe(s). Probably works with other Dallas Instruments temperature probes.
9 | * (optional) batteries and battery holder. I've had good luck with a Li-Ion 18650 cell.
10 |
11 | ## Circuit
12 |
13 | Not even worth drawing out. Data line from the DS18B20 is connected to GPIO 2 by default (D4 on Wemos D1), and has a 4.7 KΩ pullup resistor. You might want to user a lower resistor value if you have a long wire run or many sensors.
14 |
15 | ## Configuring
16 |
17 | #### WiFi
18 |
19 | If WiFi isn't configured, it'll start a setup WiFi network named something like Thermometer_XXXX. **The password is `fireitup`**. Connect to this network to configure WiFi.
20 |
21 | #### Other settings
22 |
23 | The other settings are stored as JSON in SPIFFS. When the chip is unconfigured, it starts a web server on port 80. Navigate here to edit the settings.
24 |
25 |
26 |
27 | #### Multiple sensors
28 |
29 | Sensors connected to the OneWire bus will be auto-detected. Data from all sensors will be pushed. You can configure aliases for detected device IDs in the UI or via the REST API.
30 |
31 | #### Operating mode
32 |
33 | There are two operating modes: Always On, and Deep Sleep. In Always On mode, the device will stay powered and connected to WiFi. The UI will stay running. This is good when connected to a persistent power source. Deep Sleep will push sensor readings to MQTT/HTTP and enter deep sleep. This is better when using a battery.
34 |
35 | **Breaking out of deep sleep loop**
36 |
37 | Each time the device wakes from deep sleep, it checks if it can connect to the "flag server" (configured in the JSON blob), and if the flag server sends the string **`update`**. If it does, it'll boot into settings mode.
38 |
39 | Example command:
40 |
41 | ```
42 | $ echo -ne 'update' | nc -vvl 31415
43 | ```
44 |
45 | #### OTA updates
46 |
47 | You can push firmware updates to `POST /firmware` when in settings mode. This can also be done through the UI.
48 |
49 | ## Integrations
50 |
51 | #### MQTT
52 |
53 | To push updates to MQTT, add an MQTT server and a topic prefix. You can optionally configure a username and password. Updates will be sent to the topic `/` for each detected sensor. `sensor_name` will be the device ID if an alias hasn't been added.
54 |
55 | #### HTTP
56 |
57 | To push updates to HTTP, configure a gateway server and a path for each sensor you want to push data for. Example:
58 |
59 |
60 |
61 | If you configure an HMAC secret, an HMAC of the path, body, and current timestamp will be included in the request. This allows you to verify the authenticity of the request. HMAC is computed for the concatenation of:
62 |
63 | * The path being requested on the gateway server
64 | * The body of the request
65 | * Current timestamp
66 |
67 | The signature and the timestamp are included respectively as the HTTP headers `X-Signature` and `X-Signature-Timestamp`.
68 |
69 | ## REST Routes
70 |
71 | The following routes are available when the settings server is active:
72 |
73 | * `GET /` - the settings index page
74 | * `GET /thermometers` - gets list of thermometers
75 | * `GET /thermometers/:thermometer` - `:thermometer` can either be address or alias
76 | * `GET /settings` - return settings as JSON
77 | * `PUT /settings` - patch settings. Body should be JSON
78 | * `GET /about` - bunch of environment info
79 | * `POST /update`
80 |
81 | [info-license]: https://github.com/sidoh/esp8266_thermometer/blob/master/LICENSE
82 | [shield-license]: https://img.shields.io/badge/license-MIT-blue.svg
83 |
--------------------------------------------------------------------------------
/circuit.fzz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sidoh/esp8266_thermometer/46abe0b877ca561747b45bb54e8be8529c73db42/circuit.fzz
--------------------------------------------------------------------------------
/lib/HTTP/ThermometerWebserver.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include