Introduction Link to heading
Integrating IoT with blockchain technology enhances data security, transparency, and reliability—crucial for IoT applications. Blockchain’s tamper-proof ledger and ability to timestamp data make it ideal for securely managing IoT information.
In this guide, we’ll build a blockchain-based IoT weather oracle using a thermistor sensor, Arduino, and Johnny-Five.js, storing real-time data on Chromia, a Layer-1 relational blockchain platform.
Project Overview Link to heading
We’ll create a weather data oracle using:
- A thermistor sensor to measure temperature
- An Arduino UNO to read sensor data
- Johnny-Five.js to communicate between Arduino and our application
- Chromia blockchain to securely store and timestamp the data
The final code for this project is available on GitHub.
Why Chromia and Node.js? Link to heading
Chromia suits this project because:
- Simplicity and Speed: Its SQL-based architecture allows for rapid prototyping, enabling us to build this weather oracle in under two hours.
- Customizable Fee Structures: Tailored to meet project-specific needs.
- Efficient Data Handling: Chromia ensures that once data is written, reading it is free and unlimited.
- Developer-Friendly Tools: Simplifies development with tools like Postchain client
We’re using Node.js and Johnny-Five.js to streamline development by coding everything in Typescript/JavaScript.
Prerequisites Link to heading
Hardware Link to heading
- Thermistor
- 10k Ohm Resistor
- Jumper wires
- Breadboard
- Arduino UNO R4 Wifi (or any board that Johnny-Five supported)
Software Link to heading
- Node.js and NPM
- Arduino IDE
- PostgreSQL
- Chromia CLI
Setup Link to heading
Step-by-Step Guide Link to heading
1. Setting up Chromia Link to heading
a. Initialize the project:
chr create-rell-dapp iot
cd iot
b. Edit src/main.rell
: https://github.com/superoo7/chromia-iot-demo/blob/main/src/main.rell
Let me explain the code
module;
entity temperature {
address: byte_array;
temperature: decimal;
created_at: integer = op_context.last_block_time;
}
This code defines a temperature
entity in the Chromia blockchain. It has three fields:
address
: Stores the address of the IoT device (in this case, our Arduino)temperature
: Stores the temperature readingcreated_at
: Automatically stores the timestamp of when the data was added to the blockchain
operation add_temperature(temperature: decimal) {
val addr = op_context.get_signers()[0];
create temperature (
address = addr,
temperature,
);
}
This operation allows adding new temperature readings to the blockchain:
- It takes a
temperature
parameter op_context.get_signers()[0]
gets the address of the account sending the transactioncreate temperature (...)
creates a new temperature entry in the blockchain
query get_temperatures(addr: byte_array) {
return temperature @* {
.address == addr
} (
.address,
.temperature,
.created_at,
);
}
This query function retrieves temperature data:
- It takes an
addr
parameter to filter results by a specific IoT device @*
retrieves all matching records- It returns the address, temperature, and timestamp for each record
c. Deploy the code:
chr node start
d. Set up Chromia client:
npm init -y
npm i typescript ts-node postchain-client
mkdir board
touch board/chromia.ts
e. Edit board/chromia.ts
: https://github.com/superoo7/chromia-iot-demo/blob/main/board/chromia.ts
Let me explain the code:
const signatureProvider = newSignatureProvider({
privKey: "0101010101010101010101010101010101010101010101010101010101010101",
});
This creates a signature provider with a hardcoded private key. In a real application, you’d use a secure method to manage private keys.
export async function createLocalClient() {
if (cachedClient) {
return cachedClient;
}
const client = await createClient({
nodeUrlPool: [localClient],
blockchainIid: 0,
});
cachedClient = client;
return client;
}
This function creates and caches a Chromia client:
- It checks if a client already exists to avoid creating multiple connections
- If not, it creates a new client connected to the local Chromia node
export async function addTemperature(temperature: number) {
const client = await createLocalClient();
await client.signAndSendUniqueTransaction(
{
name: "add_temperature",
args: [String(temperature)],
},
signatureProvider
);
}
This function adds a temperature reading to the blockchain:
- It gets the Chromia client
- It signs and sends a transaction to call the
add_temperature
operation we defined earlier
2. Setting up Arduino Link to heading
a. Connect the hardware:
- Connect the thermistor to Analog Pin A0
- Use a 10K Ohm resistor as a pull-down resistor
b. Install libraries
npm i --save johnny-five
npm i --save-dev @types/johnny-five
c. Create board/main.ts
:
import five from "johnny-five";
const board = new five.Board();
const beta = 3950;
const resistance = 10;
board.on("ready", function () {
const sensor = new five.Sensor({
pin: "A0",
freq: 1000,
threshold: 10,
});
sensor.on("change", async function () {
// @ts-ignore
const analogValue = this.scaleTo(0, 1023);
const { celsius } = analogValueToTemperature(analogValue);
console.log(celsius);
});
});
function analogValueToTemperature(val: number) {
const celsius =
beta /
(Math.log(((1025.0 * resistance) / val - resistance) / resistance) +
beta / 298.0) -
273.0;
const fahrenheit = 1.8 * celsius + 32.0;
return {
celsius,
fahrenheit,
};
}
Let me explain the code:
const board = new five.Board();
const beta = 3950;
const resistance = 10;
board.on("ready", function () {
const sensor = new five.Sensor({
pin: "A0",
freq: 1000,
threshold: 10,
});
// ... (sensor event handling)
});
This code sets up the Arduino board and sensor:
- It creates a new Johnny-Five board object
beta
andresistance
are constants related to the thermistor calculations- When the board is ready, it sets up a sensor on analog pin A0, reading every 1000ms (1 second)
function analogValueToTemperature(val: number) {
const celsius =
beta /
(Math.log(((1025.0 * resistance) / val - resistance) / resistance) +
beta / 298.0) -
273.0;
const fahrenheit = 1.8 * celsius + 32.0;
return {
celsius,
fahrenheit,
};
}
This function converts the analog reading from the thermistor to temperature:
- It uses the Steinhart-Hart equation to calculate temperature in Celsius
- It also calculates the Fahrenheit equivalent
3. Integrating Arduino with Chromia Link to heading
Update board/main.ts
:
import five from "johnny-five";
import { addTemperature } from "./chromia";
// ... (previous code)
board.on("ready", function () {
const sensor = new five.Sensor({
pin: "A0",
freq: 1000,
threshold: 10,
});
sensor.on("change", async function () {
// @ts-ignore
const analogValue = this.scaleTo(0, 1023);
const { celsius } = analogValueToTemperature(analogValue);
console.log(celsius);
await addTemperature(celsius);
});
});
// ... (rest of the code)
This code runs whenever the sensor detects a change:
- It scales the analog reading to a 0-1023 range
- It converts the analog value to temperature
- It logs the temperature to the console
- It calls
addTemperature
to store the reading on the Chromia blockchain
By understanding these code sections, you can see how the project combines hardware input (thermistor readings via Arduino), data processing (converting analog values to temperature), and blockchain integration (storing temperature data on Chromia). This creates a secure, decentralized IoT weather oracle.
Running the Project Link to heading
- Start the Chromia node:
chr node start
- Run the main script:
ts-node board/main.ts
You should now see temperature readings being logged and stored on the Chromia blockchain.
Conclusion Link to heading
You’ve successfully built a blockchain-based IoT weather oracle using Arduino and Chromia. This project demonstrates how to securely store and manage IoT data on a blockchain, providing a foundation for more complex IoT applications.