Python Forum

Full Version: display multiple sensors on webpage python flask jinja
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi,
I am a bit stuck,There are plenty of tutorials and forum replies for one DS18B20 sensors but I cannot find any for multiple sensors that dont use esp826 or something else. My code (below) displays the temperature of 11 senrors in the console, but I am stuck with display more than one on a web page. i have seperated my code into different modules to keep things clean and so I can import them as I need, The first is nested dictionaries with the 11 sensors
sensorsID = {
    1 : {'name':'top Cylinder','ID': '28-020f92456b1b'},
    2 : {'name':'Middle Cylinder','ID': '28-000398430420'},
    3 : {'name':'Bottom Cylinder','ID': '28-03170017b5ff'},
    4 : {'name':'Boiler output','ID': '28-0212924519b0'},
    5 : {'name':'Boiler Input','ID': '28-000798430de0'},
    6 : {'name':'Kitchen Output','ID': '28-0202924581e6'},
    7 : {'name':'kitchen Return','ID': '28-02169245238b'},
    8 : {'name':'Back Area Output','ID': '28-0317000e43ff'},
    9 : {'name':'Back Area Return','ID': '28-0317003f1cff'},
    10 : {'name':'House Output','ID': '28-0416c4a3a0ff'},
    11 : {'name':'House Return','ID': '28-021692451c79'}
}
the next is the code to read these sensors,
def read_sensor(sensorID):  
    tempfile = open("/sys/bus/w1/devices/"+ sensorID +"/w1_slave")
    thetext = tempfile.read()
    tempfile.close()
    tempdata = thetext.split("\n") [1].split(" ")[9]
    temperature = float(tempdata[2:])
    temp_sensor = temperature / 1000
    return (temp_sensor)
the next is the code that works in terminal
from mySensorModule import read_sensor
from mySensors import sensorsID
import time

for sensor in sensorsID:
    print("The temperatue of ",sensorsID[sensor]['name'],
            " is ",read_sensor(sensorsID[sensor]['ID']))
But the problem arises when i try to display this in a webpage, I can display one sensor but not all, Here is the code I have tried but I get an error; sensors.py
from flask import (
    Blueprint, flash, g, redirect, render_template, request, url_for
)
from werkzeug.exceptions import abort
from mySensorModule import read_sensor
from homeHeating.auth import login_required
from homeHeating.db import get_db
from mySensorModule import read_sensor
from mySensors import sensorsID
import time


@bp.route('/sensors')
@login_required
def sensors():
    for sensor in sensorsID:
        name=sensorsID[sensor]['name'],
        temp=read_sensor(sensorsID[sensor]['ID']
        
    templateData = {
       'name' : name,
       'ID' : ID
       }
        return render_template('sensors/sensors.html', **templateData)
Error:
File "/home/pi/heating/homeHeating/sensors.py", line 20 templateData = { ^ SyntaxError: invalid syntax
this code is an adaptation of matt richardsons tutorial the html script looks like this;
{% extends 'base.html' %}

{% block header %}
  <h1>{% block title %}Sensors{% endblock %}</h1>
    <a class="action" href="{{ url_for('sensors.addsensor') }}">New Sensor</a>
{% endblock %}{% block devises %}
  {% for sensor in sensorsID %}
    <p>The {{ name }}
    the temperature of {{ name }} is {{ temp }}
    </p>
   {% endfor %}
{% endblock %}
if I use the origional code with this template no sensors are displayed, I hope you are able to follow this! Any help is needed.
Paul
On line 18, you're missing a closing parenthesis. That's causing the syntax error.

Also, the comma at the end of line 17 should not be there.
To give a example.
So i send whole dictionary and do loop on client side with jinja2.
from flask import Flask, render_template, jsonify, request

sensors_id = {
    1 : {'name':'top Cylinder','ID': '28-020f92456b1b'},
    2 : {'name':'Middle Cylinder','ID': '28-000398430420'},
    3 : {'name':'Bottom Cylinder','ID': '28-03170017b5ff'},
    4 : {'name':'Boiler output','ID': '28-0212924519b0'},
    5 : {'name':'Boiler Input','ID': '28-000798430de0'},
    6 : {'name':'Kitchen Output','ID': '28-0202924581e6'},
    7 : {'name':'kitchen Return','ID': '28-02169245238b'},
    8 : {'name':'Back Area Output','ID': '28-0317000e43ff'},
    9 : {'name':'Back Area Return','ID': '28-0317003f1cff'},
    10 : {'name':'House Output','ID': '28-0416c4a3a0ff'},
    11 : {'name':'House Return','ID': '28-021692451c79'}
}

app = Flask(__name__)
@app.route('/')
def index():
   return render_template("index.html", sensors_id=sensors_id)

if __name__ == '__main__':
   app.run(debug=True) 
index.html:
<!doctype html>
<html>
  
<head>
  <title>Some title</title>
  <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}" />
</head>

<body>
  <div id="start">
    <h1>Start page</h1>
    <table>
      {% for key, value in sensors_id.items() %}
      <tr>
        <th> {{ key }} </th>
        <td> {{ value }} </td>
      </tr>
      {% endfor %}
    </table>
  </div>
</body>

</html>
So a little style of Table,it can look like this.
[Image: pVhwQc.jpg]
Thank you so much for your replies stullis
Quote:On line 18, you're missing a closing parenthesis. That's causing the syntax error.

Also, the comma at the end of line 17 should not be there.
this removes the syntax error, (it gave me another but I was able to remove that as well) Now it is the jinja template that does not display the data
@snippsnap Thank you so much for your reply, in my badly worded question I need to be able to "read_sensor" each value of the dictionary and then display this, I have not had time to digest your reply but I think I can use your html code to display the readings; I will get back this evening with more information. But thank you both for HELPING ME!!!!!!!!!! It is so kind of you!!
regards
Paul
SOLVED!!!
Thank you guys! I have solved it. Heres my code for sensors.py
@bp.route('/sensors')
@login_required
def sensors():
    return render_template('sensors/sensors.html',
                          sensorsID=sensorsID, read_sensor=read_sensor)
and here is my code for sensors.html
{%block content %}
    <h1>Sensors temperature list</h1>
      <table>
        {% for i in sensorsID %}
          <tr>
            <th> Sensor {{ sensorsID[i]['name'] }}</th>
            <td> temperature is {{ read_sensor(sensorsID[i]['ID']) }} </td>
          </tr>
        {% endfor %}
      </table>
{% endblock %}
this gives this (well I would have put a screen shot here but I cant work out how to do it!)
My warmest regards to stullis and snippsat
This could be improved:
def read_sensor(sensorID):  
    tempfile = open("/sys/bus/w1/devices/"+ sensorID +"/w1_slave")
    thetext = tempfile.read()
    tempfile.close()
    tempdata = thetext.split("\n") [1].split(" ")[9]
    temperature = float(tempdata[2:])
    temp_sensor = temperature / 1000
    return (temp_sensor)
Using pathlib and regular expression and context manager.
from pathlib import Path
import re


DS18B20 = re.compile(r't=(\d{5})')
# regex to get the temperature
# seek for t=5-digits


def read_sensor(sensorID):
    device = Path('/sys/bus/w1/devices') / str(sensorID) / 'w1_slave'
    with device.open() as fd:
        data = fd.read()
    match = DS18B20.search(data)
    # match is None, if nothing was found
    if not match:
        raise Exception('Could not read data from sensor {}'.format(sensorID))
    temperature = float(match.group(1))
    # group 1 is the first match in parenthesis 
    return temperature / 1000
BTW: I prefer single quotes. This does not mean, that you have to use single quotes.
Awsome DeaD_EyE
I will try this out and investigate pathlib
Thank for your advice.
Regards
Paul