Fork me on GitHub

Project Notes

#811 ESP8266 (ESP-01) IoT Temperature Sensor

Using MicroPython on an ESP8266 (512kb ESP01) to capture DS18S20 temperature readings and log to a cloud data collection service (Ubidots).

Build

Notes

I’m reviving this very simple project from an initial investigation I did way back in 2016 but never got around to posting after watching the “MicroPython on ESP8266 update” (see the video below).

At the time, it was quite exiting to see python running on the amazingly cheap early generations of the ESP8266. One of the demonstrations in the video showed:

  • reading temperature from a DS1822-class 1-wire device
  • posting the data to the Xively cloud service

clip

Objectives

Here’s what I want to attempt again, now in 2026:

  • using the ESP-01 512kb ESP8266 with the latest MicroPython
  • read temperatures from a DS18S20 1-wire device
  • post the data to a cloud service

Circuit Design

Here’s the basic setup:

Designed with Fritzing: see esp-01-temperature-logger.fzz.

bb

schematic

bb_build

Step 1: Logging to Console

After booting the ESP8266 with MicroPython, I connect using screen:

export ESP_PORT=$(ls /dev/tty.wchusb*)
screen ${ESP_PORT} 115200

The first test is to read the DS18S20 sensor and log the temperature to the console. I simply paste the source from log-temperature-to-console.py into the REPL:

=== import ds18x20
=== from machine import Pin
===
=== pin = Pin(2)
=== ow = onewire.OneWire(pin)
=== ds = ds18x20.DS18X20(ow)
=== roms = ds.scan()
===
=== def read_temps(ds, roms):
===     while True:
===         ds.convert_temp()
===         time.sleep(1)
===         for rom in roms:
===             addr = ''.join('{:02x}'.format(b) for b in rom)
===             temp = ds.read_temp(rom)
===             print(addr, temp)
===
>>> read_temps(ds, roms)
28ff1002831501f8 25.0625
28ff1002831501f8 25.125
...

All good! We are successfully capturing temperature readings from the DS18S20 sensor.

log-console

For more information on the python API calls, see:

Sending the Readings to a Cloud Data Service

Now we have temperature readings, the next step is to send the data somewhere useful.

The original demo used the Xively cloud service, but that no longer exists….

What happened to Xively?

Xively was an IoT platform originally founded in 2007 (initially named Pachube) and later rebranded as Cosm and then Xively. It provided cloud services to connect, manage, and gather data from internet-connected devices—handling device messaging (MQTT), dashboards, analytics, and APIs.

In 2018, Google acquired Xively from LogMeIn for about $50 M and integrated its technology and team into Google Cloud’s IoT efforts.

Xively as a standalone platform no longer exists. Its domain redirects to Google Cloud IoT information, and the original service was absorbed into Google’s offerings.

Google continued IoT work under Google Cloud IoT Core, which built on parts of Xively’s tech. However Google Cloud IoT Core was officially retired in August 2023, with device connections and APIs shut down, forcing users to migrate to other IoT platforms or partner solutions.

An alternative: Ubidots

It’s now 2026, and things have changed quite a bit since 2016:

  • huge churn in cloud/IoT platforms - seems no-one survived!
  • pretty much everyone now does TLS/HTTPS (usually only) by default , so constrained devices struggle to even connect

After much searching and review, I have found one that fits the bill: Ubidots:

  • still supports an HTTP interface
  • simple API for posting data
  • and has a free plan to allow no-cost review

Testing Ubidots from the console

Before trying to do this on the ESP8266, let’s test the API from a desktop device. In my case, macOS.

We first need to use our account API key generate a token that can be used in subsequent dat a requests:

$ curl -X POST "https://industrial.api.ubidots.com/api/v1.6/auth/token" \
-H "x-ubidots-apikey: ${UDIBOTS_API_KEY}" \
-H "Content-Type: application/json"
{"token": "my-new-token"}
$ export UDIBOTS_TOKEN="my-new-token"

Now we have an API token, I can post data to the standard HTTPS endpoint:

$ curl -X POST "https://industrial.api.ubidots.com/api/v1.6/devices/test-device" \
-H "X-Auth-Token: ${UDIBOTS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"temperature":{"value": 23.1, "units": "C"}}'
{"temperature":[{"status_code":201}]}

Now let’s verify we can also post data to the HTTP endpoint:

$ curl -X POST "http://industrial.api.ubidots.com/api/v1.6/devices/test-device" \
-H "X-Auth-Token: ${UDIBOTS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"temperature":{"value": 23.2, "units": "C"}}'
{"temperature":[{"status_code":201}]}

That all works well, and I’m seeing the data immediately in the Ubidots web console:

ubidots-1

Sending To Ubidots from MicroPython

Now let’s try the web request from MicroPython on the ESP-01.

The ESP device needs to be connected to the network first. Use wifi.py to connect if not already connected.

def do_connect():
    import network

    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network...')
        wlan.connect('mySSID', 'password')
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())

do_connect()

See ubidots.py, which I pasted directly into the ESP repl to execute:

import socket
import ujson

HOST = "industrial.api.ubidots.com"
PORT = 80
PATH = "/api/v1.6/devices/test-device"
TOKEN = "my-api-token"

payload = {
    "temperature": {
        "value": 22.1, "units": "C"
    }
}

body = ujson.dumps(payload)

addr = socket.getaddrinfo(HOST, PORT)[0][-1]
s = socket.socket()
s.connect(addr)

request = (
    "POST {} HTTP/1.1\r\n"
    "Host: {}\r\n"
    "X-Auth-Token: {}\r\n"
    "Content-Type: application/json\r\n"
    "Content-Length: {}\r\n"
    "Connection: close\r\n"
    "\r\n"
    "{}"
).format(PATH, HOST, TOKEN, len(body), body)

s.send(request.encode())
print(s.recv(1024))
s.close()

We now see the additional datapoints in the web console:

ubidots-2

For more information see:

Logging Temperature To Ubidots

Now we are ready to pull it all together: capture the temperature readings from the DS18S20 sensor, and post the results to Ubidots

The source is in log-temperature-to-ubidots.py, which I paste into the MicroPython REPL:

import socket
import ujson
import time
import onewire
import ds18x20
from machine import Pin

HOST = "industrial.api.ubidots.com"
PORT = 80
DEVICES_PATH = "/api/v1.6/devices/"
TOKEN = "my-api-token"
ONEWIRE_PIN = 2


def post_temperature(api_host_address, device_name, temperature):
    payload = {
        "temperature": {
            "value": temperature, "units": "C"
        }
    }
    body = ujson.dumps(payload)

    s = socket.socket()
    s.connect(api_host_address)

    request = (
        "POST {}{} HTTP/1.1\r\n"
        "Host: {}\r\n"
        "X-Auth-Token: {}\r\n"
        "Content-Type: application/json\r\n"
        "Content-Length: {}\r\n"
        "Connection: close\r\n"
        "\r\n"
        "{}"
    ).format(DEVICES_PATH, device_name, HOST, TOKEN, len(body), body)

    s.send(request.encode())
    print(s.recv(1024))
    s.close()

def read_and_log_temps(ds, api_host_address):
    roms = ds.scan()
    while True:
        ds.convert_temp()
        time.sleep(1)
        for rom in roms:
            device_name = 'esp8266-' + ''.join('{:02x}'.format(b) for b in rom)
            temperature = ds.read_temp(rom)
            print('Device:', device_name, 'Latest reading:', temperature)
            post_temperature(api_host_address, device_name, temperature)
        time.sleep(9)

ubidots_addr = socket.getaddrinfo(HOST, PORT)[0][-1]
ds = ds18x20.DS18X20(onewire.OneWire( Pin(ONEWIRE_PIN)))

read_and_log_temps(ds, ubidots_addr)

And that works very nicely:

log-temperature-to-ubidots

One doesn’t need to keep the console open while the script runs, but if one does, we see the temperature readings and API postings logged on screen:

log-temperature-to-ubidots-console

Next steps?

So we have a basic data collection process running on the ESP-01.

logging-2

But there are issues:

  • the Ubidots token appears to only have a 1 hour life.
    • I can’t find docs to confirm this.
    • It does mean, however, that my code above is only good for ~hour.
    • It needs to be enhanced to re-generate tokens as required in order to run for periods over 1 hour
  • the 512kb ESP-01 doesn’t have a filesystem to allow boot sequences to be specified
    • means that every time I restart the ESP-02, I have to reload the script

Rather than try and work around these issues with the ESP-01, I think it would be better to try one of the more capable ESP8266 boards first.

Credits and References

About LEAP#811 ESP8266MicroPythonDS18S20SensorsUbidots

This page is a web-friendly rendering of my project notes shared in the LEAP GitHub repository.

Project Source on GitHub Return to the LEAP Catalog
About LEAP

LEAP is my personal collection of electronics projects - usually involving an Arduino or other microprocessor in one way or another. Some are full-blown projects, while many are trivial breadboard experiments, intended to learn and explore something interesting.

Projects are often inspired by things found wild on the net, or ideas from the many great electronics podcasts and YouTube channels. Feel free to borrow liberally, and if you spot any issues do let me know or send a pull-request.

NOTE: For a while I included various scale modelling projects here too, but I've now split them off into a new repository: check out LittleModelArt if you are looking for these projects.

Project Gallery view the projects as an image gallery Notebook reference materials and other notes Follow the Blog follow projects and notes as they are published in your favourite feed reader