The little board in your hand streams temperature & humidity to your own live dashboard on tissue.systems. Everything on the cloud side is already prepared — a Cell to receive the readings and a database to keep them are waiting in your account. Three steps and you're live. Then the real fun starts: it's all yours to hack.
tissue-sense-XXXX.
tissue-sense-XXXX
network. A setup page opens by itself — pick your home Wi-Fi and enter its
password. The device then joins your Wi-Fi, links itself to your account,
and starts reporting.
The hardware is two off-the-shelf parts, about $6 total, and no soldering if you pick the right versions (though many D1 Mini boards ship with the header pins loose in the bag — check the listing, or warm up the iron):
Wiring — the sensor's data line goes to
D4 (the pin silk-printed "2", next to GND):
+ → 3V3 ·
out → D4 ·
− → G. Done — the pull-up is on the little board.VCC → 3V3, pin 2
DATA → D4, pin 3 unconnected, pin 4
GND → G — plus a 10 kΩ resistor
between pin 1 and pin 2. Without it every read comes back
NaN.A self-built board doesn't have a QR sticker, so it skips the tap-to-onboard flow. Instead you set up both halves yourself — it's four steps:
git clone https://github.com/tissue-systems/demo-cbc-sense.git,
then in cell/: delete the two account-pin lines in
ribo.toml, run ribo db create cbc-sense and
ribo deploy (install ribo from
tissue.systems/download
and ribo login first — full walkthrough in the
deploy section below).ribo sensor add cbc-sense and give it the credentials —
exactly the connect-your-own-device path below, with
the same firmware ideas from the firmware
section (the MicroPython route is the fastest from zero).The dashboard, the alerts, the firmware — every part of this demo is open and editable, and your free account can deploy code to a live URL in seconds. Here's the tour, from easiest to most adventurous:
Everything your device and dashboard run is public at
github.com/tissue-systems/demo-cbc-sense:
cell/ is the backend (one commented JavaScript file + config),
firmware/ is the C++ the board runs, enclosure/ is the
3D-printable case.
git clone https://github.com/tissue-systems/demo-cbc-sense.git cd demo-cbc-sense
A Cell is a JavaScript function on a live URL. You'll need ribo, the tissue CLI — grab it from tissue.systems/download, then:
# install (macOS Apple Silicon shown — see the download page for others) curl -L https://tissue.systems/download/latest/ribo-macos-arm64 -o ribo chmod +x ribo && sudo mv ribo /usr/local/bin/ribo ribo login # opens your browser to authenticate # deploy your own copy of the demo backend: cd cell # edit ribo.toml first: delete the two "account" lines (it deploys to YOUR # account) and pick any cell name you like ribo db create cbc-sense # the database the Cell stores readings in ribo deploy # → https://<name>.<your-subdomain>.tissue.dev
That's a second, fully-yours copy of the dashboard — separate from the one your
account came with, so you can break it freely. Edit cell/cell.js,
run ribo deploy again, refresh. That's the whole loop.
The demo Cell already contains a full alert engine — sensor-offline detection and temperature/humidity thresholds, pushed to your phone as Telegram messages. It just needs a bot token. Telegram is free, and this works the same on iOS and Android:
@BotFather,
send /newbot, follow the two prompts, and copy the HTTP token it
gives you (looks like 1234567890:AA…).@userinfobot and it replies
with your numeric id.Then store both values (encrypted, server-side) and redeploy:
# "cbc-sense" = your cell's name — swap it if you picked a different one ribo vault set cbc-sense TELEGRAM_BOT_TOKEN # paste the @BotFather token ribo vault set cbc-sense TELEGRAM_CHAT_ID # paste your numeric id ribo deploy
Alert thresholds live in cell/ribo.toml — set
ALERT_TEMP_MAX_C = "28" (or any min/max for temperature and
humidity), redeploy, and your phone buzzes when a limit is crossed and again
when it recovers. The offline dead-man's switch needs no configuration: if the
sensor goes silent, you get a 🔴 message; when it's back, ✅.
cell/cell.js explains everything in more detail).
The whole dashboard — charts, tiles, colors, the blinking offline alarm — is one
HTML page inside cell/cell.js (the PAGE constant), with
no build step and no frameworks. Easy first hacks:
--temp / --hum CSS
variables at the top of the page style both charts.drawChart's label functions./api/series shows the query pattern).
The board is a Wemos D1 Mini (ESP8266) and the firmware is one commented file,
firmware/src/main.cpp. PlatformIO
builds and flashes it — a one-command install:
# macOS brew install platformio # or: pipx install platformio # Linux pipx install platformio sudo usermod -aG dialout $USER # serial-port access; log out & back in # Windows (PowerShell, needs Python 3) py -m pip install --user pipx && py -m pipx ensurepath pipx install platformio # reopen the terminal between the two
Plug the board in with a data USB cable (many bundled cables are
charge-only — the board powers up but never shows up) and confirm it's visible
with pio device list. Windows only: if no COM port appears, install
the CH340 driver;
macOS and Linux have it built in. Then:
cd firmware make config # one-time: creates include/config.h make upload # build + flash over USB make monitor # watch the live serial log
Anything deeper — per-OS details, no-make Windows commands, a
troubleshooting table — is in
firmware/README.md,
right next to the code.
Ideas, roughly in order of ambition:
REPORT_INTERVAL_MS in
include/config.h. (Regular accounts are rate-controlled to one
reading per minute.)reportOnce() and publish a new metric with
publishMetric("pressure", v, "hPa"). New metrics need a
matching chart — see the dashboard section above.cmd/# topic and your Cell can blink the LED, start a
motor, or move a servo — full device + Cell code in
Cloud to
device. (Power motors/servos from their own supply, not the board's
3V3 — share only ground.)ESP.deepSleep()), wake → read → publish → sleep. One wire is
mandatory: jumper D0 to RST, or the board can
never wake itself.
The same board runs MicroPython — a full
Python REPL on the device, no compiler, no PlatformIO. Flashing it takes two
commands with esptool (pipx install esptool) and the
latest ESP8266_GENERIC
image:
# find your serial port (macOS: /dev/cu.usbserial-*, Linux: /dev/ttyUSB0, Windows: COMx) esptool.py --port /dev/cu.usbserial-210 erase_flash esptool.py --port /dev/cu.usbserial-210 --baud 460800 \ write_flash --flash_size=detect 0 ESP8266_GENERIC-*.bin # talk to the Python REPL (pipx install mpremote); Ctrl-] to exit mpremote repl # copy a script so it runs at boot, then restart the board mpremote cp main.py :main.py mpremote reset
From there, the built-in dht module and the umqtt
client (bundled in most builds; otherwise
import mip; mip.install("umqtt.simple")) read the
sensor and publish to tissue — the
Connect Your Own
Device guide has a complete, copy-paste MicroPython reporting script
(Wi-Fi setup, TLS, reconnects included). You'll need device credentials from
ribo sensor add, since MicroPython replaces the demo firmware —
including its QR onboarding. To go back to the stock demo firmware, just
make upload from firmware/ again.
Anything that can speak MQTT over TLS can stream into tissue — not just this board. Register a device under any of your Cells and you get its credentials (shown once — save them):
ribo sensor add cbc-sense # device_id dev_a1b2c3d4 ← MQTT username # token key_<64 hex> ← MQTT password # topic tissue/<account>/<device>/<metric>
Device already speaks MQTT? (Tasmota, ESPHome, Zigbee2MQTT
bridges, a home-automation hub…) Point it at
ingest.tissue.dev:8883 (TLS), username = device_id, password =
token, and publish JSON like {"value":21.4,"unit":"C"} to topics
inside its prefix — e.g. …/env/temperature. Each publish lands in
your Cell's sensor() handler.
No MQTT on the device? Two good paths: add an MQTT client to its
firmware (MicroPython's umqtt, Arduino's PubSubClient — the
Connect Your Own
Device guide has a complete MicroPython example, including flashing
MicroPython onto a bare board), or let a small bridge do the
talking: a Raspberry Pi, an always-on laptop, or a Node-RED flow that reads the
device however it likes (HTTP, serial, Bluetooth) and republishes over MQTT.
From your terminal, one reading looks like:
mosquitto_pub -h ingest.tissue.dev -p 8883 --tls-use-os-certs \
-u dev_a1b2c3d4 -P key_... \
-t 'tissue/acct_9c3f21ab/dev_a1b2c3d4/env/temperature' \
-m '{"value":21.4,"unit":"C"}'
And it works both ways: a device can subscribe to its
own cmd/# topic, and your Cell can publish commands to it — blink
an LED, start a motor, sweep a servo. Device-side and Cell-side code for both
MicroPython and Arduino is in
Cloud to device.
Every device gets its own key, its own topic namespace, and its own kill switch — the security model is written up in Onboarding a Device. Report once a minute per metric; managing, disabling, and rotating devices is in Managing Devices.
Made with tissue. Questions? tissue Discord · tissue support · your dashboard