Site Map - skip to main content

Hacker Public Radio

Your ideas, projects, opinions - podcasted.

New episodes every weekday Monday through Friday.
This page was generated by The HPR Robot at


hpr4311 :: LoRaWAN and the Things Stack

Lee sets up some temperature and humidity sensors

<< First, < Previous, Next > Latest >>

Hosted by Lee on Monday, 2025-02-10 is flagged as Clean and is released under a CC-BY-SA license.
iot, lorawan. 1.
The show is available on the Internet Archive at: https://archive.org/details/hpr4311

Listen in ogg, spx, or mp3 format. Play now:

Duration: 00:10:09

general.

I have set up some LoRaWAN temperature and humidity sensors, and am using the Things Stack to collect the data.


This gets processed via a web-hook and rendered as a graph.


The LoRaWAN Alliance - https://lora-alliance.org


Mastering LoRaWAN - https://www.amazon.com/Mastering-LoRaWAN-Comprehensive-Communication-Connectivity-ebook/dp/B0CTRH6MV6


The Things Industries - https://thethingsindustries.com


server.py

import json
import sqlite3
import logging
from http.server import BaseHTTPRequestHandler, HTTPServer

rooms = {
    'eui-24e12*********07': 'living-room',
    'eui-24e12*********54': 'hall',
    'eui-24e12*********42': 'downstairs-office',
    'eui-24e12*********35': 'kitchen',
    'eui-24e12*********29': 'conservatory',
    'eui-24e12*********87': 'landing',
    'eui-24e12*********45': 'main-bedroom',
    'eui-24e12*********89': 'upstairs-office',
    'eui-24e12*********38': 'spare-bedroom',
    'eui-24e12*********37': 'playroom'
};

# Configure logging
logging.basicConfig(filename="server_log.txt", level=logging.INFO, format="%(asctime)s - %(message)s")

# Define the web server handler
class MyServerHandler(BaseHTTPRequestHandler):

    # Handle POST requests
    def do_POST(self):
        length = int(self.headers.get('Content-Length'))
        data = self.rfile.read(length).decode('utf-8')

        try:
            # Validate and parse JSON data
            json_data = json.loads(data)
            logging.info(f"Received valid JSON data: {json_data}")

            # Write the data to database
            id = json_data["end_device_ids"]["device_id"]
            room = rooms.get(id)
            readat = json_data["uplink_message"]["rx_metadata"][0]["time"]
            temp = json_data["uplink_message"]["decoded_payload"]["temperature"]
            hum = json_data["uplink_message"]["decoded_payload"]["humidity"]
            conn = sqlite3.connect('data.db')
            sql = """CREATE TABLE IF NOT EXISTS data (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                room TEXT,
                readat DATETIME,
                temp DECIMAL(4,1),
                hum DECIMAL(4,1)
            );"""
            conn.execute(sql)
            sql = "INSERT INTO data (room, readat, temp, hum) VALUES (?, ?, ?, ?)"
            conn.execute(sql, (room, readat, temp, hum))
            conn.commit()
            conn.close()

            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(bytes("Data received and logged!", "utf-8"))

        except json.JSONDecodeError:
            logging.error("Invalid JSON data received.")
            self.send_response(400)  # Bad Request
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(bytes("Invalid JSON format.", "utf-8"))

        except PermissionError:
            logging.error("File write permission denied.")
            self.send_response(500)  # Internal Server Error
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(bytes("Server error: Unable to write data to file.", "utf-8"))

# Start the server
server_address = ('0.0.0.0', 12345)  # Customize host and port if needed
httpd = HTTPServer(server_address, MyServerHandler)
print("Server started on http://localhost:12345")
httpd.serve_forever()


process.php

<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<canvas id="temp" style="height:50vh"></canvas>
<canvas id="hum" style="height:50vh"></canvas>
<script>
<?php

    $colors = [
        '#FF9999',  // Light red
        '#FFCC99',  // Light orange
        '#FFFF99',  // Light yellow
        '#CCFF99',  // Light lime green
        '#99FF99',  // Light green
        '#99FFCC',  // Light teal
        '#99FFFF',  // Light sky blue
        '#99CCFF',  // Light blue
        '#9999FF',  // Light violet
        '#CC99FF',  // Light lavender
        '#FF99FF',  // Light pink
        '#FFCCFF', // Light rose
        '#FFD5D5',  // Light salmon
        '#FFDDAA',  // Light peach
        '#FFE0E0',  // Light beige
        '#FFF0F0' // Light ivory
    ];

    $results = [
        'living-room' => [
            'temperature' => [],
            'humidity' => []
        ],
        'hall' => [
            'temperature' => [],
            'humidity' => []
        ],
        'downstairs-office' => [
            'temperature' => [],
            'humidity' => []
        ],
        'kitchen' => [
            'temperature' => [],
            'humidity' => []
        ],
        'conservatory' => [
            'temperature' => [],
            'humidity' => []
        ],
        'landing' => [
            'temperature' => [],
            'humidity' => []
        ],
        'main-bedroom' => [
            'temperature' => [],
            'humidity' => []
        ],
        'upstairs-office' => [
            'temperature' => [],
            'humidity' => []
        ],
        'spare-bedroom' => [
            'temperature' => [],
            'humidity' => []
        ],
        'playroom' => [
            'temperature' => [],
            'humidity' => []
        ]
    ];

    $labels = [];

    $db = new SQLite3('data.db');
        $sql = "SELECT room, readat, temp, hum FROM data";
        $stmt = $db->prepare($sql);
        $result = $stmt->execute();

        while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
                $where = $row['room'];

                                $tz = 'Europe/London';
                                $dt = new DateTime($row['readat']);
                                $dt->setTimezone(new DateTimeZone($tz));
                                $when = $dt->format('d/m/Y, H:i');

                $u = intdiv(date_format(date_create($row['readat']), "U"), 600);
                $temp = number_format($row['temp'], 1);
                $hum = number_format($row['hum'], 1);

        $labels[$u] = "\"$when\"";

                $results[$where]['temperature'][] = $temp;
                $results[$where]['humidity'][] = $hum;
        }

        $stmt->close();
        $db->close();

    $c = 0;
    foreach ($results as $key => $room) {
        $col = $colors[$c];
        $temp_datasets[] = "{ label: \"$key °C\",  data: [ ".implode(",", $room['temperature'])." ], borderColor: \"$col\" }";
        $hum_datasets[] = "{ label: \"$key %\", data: [ ".implode(",", $room['humidity'])." ], borderColor: \"$col\" }";
        $c++;
    }

?>
const data1 = { datasets: [ <?php echo implode(",",$temp_datasets); ?> ], labels: [<?php echo implode(",", $labels); ?>] };
const ctx1 = document.getElementById("temp").getContext("2d");
const options1 = {
  type: "line",
  data: data1,
  options: {
    elements: {
      point:{
        radius: 0
      }
    }
  }
};
const chart1 = new Chart(ctx1, options1);

const data2 = { datasets: [ <?php echo implode(",",$hum_datasets); ?> ], labels: [<?php echo implode(",", $labels); ?>] };
const ctx2 = document.getElementById("hum").getContext("2d");
const options2 = {
  type: "line",
  data: data2,
  options: {
    elements: {
      point:{
        radius: 0
      }
    }
  }
};
const chart2 = new Chart(ctx2, options2);
</script>
</body>
</html>


Temperature Chart


Graph showing temp over time in
        various rooms


Humidity Chart


Graph showing humidity over time in
        various rooms



Comments

Subscribe to the comments RSS feed.

Comment #1 posted on 2025-01-15 17:03:11 by Ken Fallon

Great insignt into LoRaWAN

This was a great look at a real world implementation of LoRaWAN, and left me wanting to know more about the topic.

Then I see the show notes and the two scripts themselves are a series of shows.

Great stuff !

Leave Comment

Note to Verbose Commenters
If you can't fit everything you want to say in the comment below then you really should record a response show instead.

Note to Spammers
All comments are moderated. All links are checked by humans. We strip out all html. Feel free to record a show about yourself, or your industry, or any other topic we may find interesting. We also check shows for spam :).

Provide feedback
Your Name/Handle:
Title:
Comment:
Anti Spam Question: What does the letter P in HPR stand for?
Are you a spammer?
Who is the host of this show?
What does HPR mean to you?