Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Newbie help combining two scripts
#1
Hi all. I'm new to Python, but have some experience in HTML/CSS/JS. I'm running Raspberry Pi to be able to monitor my daughter's rabbit in the shed outside. So far I've been able to accomplish the following:

-RPI webpage (created with a Python example script), displaying the camera (mjpeg) stream can be accessed via dynamic dns :)
-Another Python script that access the temperature sensor works in console :)

Now, my challenge here is to display the output of the temperature script on the same Python generated webpage, which displays the camera stream. I've been banging my head with this for a few days, but I just cannot grasp the thing how to "access" the temperature script output from the webpage :/ Like I said the Python code generating the webpage is not my creation, but an example from the internets.

Could someone more experienced help me accomplish this what I'm trying to achieve here? The more simple solution, the better :)
Here's the script that creates the webpage and displays the mjpeg stream:

# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server

PAGE="""\
<html>
<head>
<title>Raspberry Pi - Surveillance Camera</title>
</head>
<body>
<center><h1>Raspberry Pi - Surveillance Camera</h1></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
</body>
</html>
"""

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='1280x720', framerate=24) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    #camera.rotation = 90
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()
Here's the script that shows the temperature reading in console:

import os
import glob
import time
 
os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')
 
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
 
def read_temp_raw():
    f = open(device_file, 'r')
    lines = f.readlines()
    f.close()
    return lines
 
def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find('t=')
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        temp_f = temp_c * 9.0 / 5.0 + 32.0
        return temp_c, temp_f
	
while True:
	print(read_temp())	
	time.sleep(1)
Reply
#2
You can make an ajax request, e.g. every second, and show current temperature value.
To do this, you need to implement end-point for this ajax request, e.g.

...
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))
      ....

Don't forget to copy content of your second script (without while block at the end) to the first one (or if they
are in the same folder, try to insert from second_script import read_temp in the beginning of the first script.)

Further, you need to make continuous ajax requests from your webpage, so you need to include some js-code
into webpage (into your html-template).

For now, you can try to run all, and check your_url/get-temp path. You should get current temperature
as a json response.

Now, you need to add some js-code to your webpage template:

PAGE="""\
<html>
<head>
<title>Raspberry Pi - Surveillance Camera</title>
</head>
<body>
<center><h1>Raspberry Pi - Surveillance Camera</h1></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>

<center><div id="temperature"></div></center>

<script>

function updateTemp(){

window.fetch('http://your_url/get-temp', {method: 'get'}).then(r => r.json())
  .then(function(data){
   let el = document.getElementById('temperature')
   el.innerHTML = data.stringify() // you can do this better
})
  .catch(e => console.log("error ocurred..."))
}


// this executes only once, but you need to run it every second
updateTemp() // You probably need to run this continuously, e.g. using SetInterval function

</script>

</body>
</html>
"""
You still need to adopt this solution for your needs...
Reply
#3
Thank you for a detailed answer scidam :) Much appreciated! I hope I understood your instructions correctly. For some reason my-url/get-temp does not do anything. Also, there's no temp reading in the corresponding div :/ I don't get any errors when I run the code, so syntactically it is ok, I guess. Here's how my code looks like after editing it:
# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

import os
import glob
import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
import time
from w1thermsensor import W1ThermSensor
PAGE="""\
<html>
<head>
<title>Kanikamera</title>
<script type="text/javascript" src="/home/pi/script.js"></script>
</head>
<body>
<center><h1>Kanikamera</h1></center>
<center><h3>L&auml;mp&ouml;tila</h3></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
<center><div id="temperature"></div></center>

#This is the script for displaying the temperature on the web page
<script>
function updateTemp(){
window.fetch('http://your_url/get-temp', {method: 'get'}).then(r => r.json())
  .then(function(data){
   let el = document.getElementById('temperature')
   el.innerHTML = data.stringify() // you can do this better
})
  .catch(e => console.log("error ocurred..."))
}
 
// this executes only once, but you need to run it every second
updateTemp() // You probably need to run this continuously, e.g. using SetInterval function
</script>
</body>
</html>
"""
#This is the part to get the temperature
os.system('modprscriptobe w1-gpio')
os.system('modprobe w1-therm')
  
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
  
def read_temp_raw():
    f = open(device_file, 'r')
    lines = f.readlines()
    f.close()
    return lines
  
def read_temp():
    lines = read_temp_raw()
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = read_temp_raw()
    equals_pos = lines[1].find('t=')
    if equals_pos != -1:
        temp_string = lines[1][equals_pos+2:]
        temp_c = float(temp_string) / 1000.0
        temp_f = temp_c * 9.0 / 5.0 + 32.0
        return temp_c, temp_f

#This is the part, which makes the endpoint for the AJAX.
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))

#This is the part for the camera
class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='1280x720', framerate=24) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    #camera.rotation = 90
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()
Reply
#4
It seems that when I instead of adding the temp reading script directly into the other script I added made a reference to the temp reading script file:

from temp2 import read_temp
at the beginning of the script, it just starts to print the temps 1 time/second tto the console and the actual webpage neve "gets created". Here's the complete script file:

# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

from temp2 import read_temp 
import os
import glob
import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
import time
#from w1thermsensor import W1ThermSensor
PAGE="""\
<html>
<head>
<title>Kanikamera</title>
<script type="text/javascript" src="/home/pi/script.js"></script>
</head>
<body>
<center><h1>Kanikamera</h1></center>
<center><h3>L&auml;mp&ouml;tila</h3><h3 id="portfolio-code"></h3></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
<center><div id="temperature"></div></center>
 
<script>
 
function updateTemp(){
 
window.fetch('http://your_url/get-temp', {method: 'get'}).then(r => r.json())
  .then(function(data){
   let el = document.getElementById('temperature')
   el.innerHTML = data.stringify() // you can do this better
})
  .catch(e => console.log("error ocurred..."))
}
 
 
// this executes only once, but you need to run it every second
updateTemp() // You probably need to run this continuously, e.g. using SetInterval function
 
</script>
</body>
</html>
"""
#os.system('modprobe w1-gpio')
#os.system('modprobe w1-therm')
#  
#base_dir = '/sys/bus/w1/devices/'
#device_folder = glob.glob(base_dir + '28*')[0]
#device_file = device_folder + '/w1_slave'
#  
#def read_temp_raw():
#    f = open(device_file, 'r')
#    lines = f.readlines()
#    f.close()
#    return lines
#  
#def read_temp():
#    lines = read_temp_raw()
#    while lines[0].strip()[-3:] != 'YES':
#        time.sleep(0.2)
#        lines = read_temp_raw()
#    equals_pos = lines[1].find('t=')
#    if equals_pos != -1:
#        temp_string = lines[1][equals_pos+2:]
#        temp_c = float(temp_string) / 1000.0
#        temp_f = temp_c * 9.0 / 5.0 + 32.0
#        return temp_c, temp_f
def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))


class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='1280x720', framerate=24) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    #camera.rotation = 90
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()
Reply
#5
Quote:For some reason my-url/get-temp does not do anything
You should be able to get current temperature just by typing my-url/get-temp in browser.
Try fake temperature values instead, e.g.
self.wfile.write(json.dumps({'temp_c': 10, 'temp_f': 10}))
If this works, the problem in the block that getting temperature.
Reply
#6
(Oct-01-2020, 01:45 PM)emuola Wrote: It seems that when I instead of adding the temp reading script directly into the other script I added made a reference to the temp reading script file:

from temp2 import read_temp
at the beginning of the script, it just starts to print the temps 1 time/second tto the console and the actual webpage neve "gets created". Here's the complete script file:

# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

from temp2 import read_temp 
import os
import glob
import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
import time
#from w1thermsensor import W1ThermSensor
PAGE="""\
<html>
<head>
<title>Kanikamera</title>
<script type="text/javascript" src="/home/pi/script.js"></script>
</head>
<body>
<center><h1>Kanikamera</h1></center>
<center><h3>L&auml;mp&ouml;tila</h3><h3 id="portfolio-code"></h3></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
<center><div id="temperature"></div></center>
 
<script>
 
function updateTemp(){
 
window.fetch('http://your_url/get-temp', {method: 'get'}).then(r => r.json())
  .then(function(data){
   let el = document.getElementById('temperature')
   el.innerHTML = data.stringify() // you can do this better
})
  .catch(e => console.log("error ocurred..."))
}
 
 
// this executes only once, but you need to run it every second
updateTemp() // You probably need to run this continuously, e.g. using SetInterval function
 
</script>
</body>
</html>
"""
#os.system('modprobe w1-gpio')
#os.system('modprobe w1-therm')
#  
#base_dir = '/sys/bus/w1/devices/'
#device_folder = glob.glob(base_dir + '28*')[0]
#device_file = device_folder + '/w1_slave'
#  
#def read_temp_raw():
#    f = open(device_file, 'r')
#    lines = f.readlines()
#    f.close()
#    return lines
#  
#def read_temp():
#    lines = read_temp_raw()
#    while lines[0].strip()[-3:] != 'YES':
#        time.sleep(0.2)
#        lines = read_temp_raw()
#    equals_pos = lines[1].find('t=')
#    if equals_pos != -1:
#        temp_string = lines[1][equals_pos+2:]
#        temp_c = float(temp_string) / 1000.0
#        temp_f = temp_c * 9.0 / 5.0 + 32.0
#        return temp_c, temp_f
def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))


class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='1280x720', framerate=24) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    #camera.rotation = 90
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()

Unfortunately regardless whether there's a fixed value for the temp or not, I get nothing when trying xxx/get-temp, there's no reply (refused to connect). The xxx:8000 works fine showing the camera image. Would this help to debug this further?
Reply
#7
I expected that you modify do_GET, but not put it outside
StreamingHandler.
Your StreamingHandler should look like the following:

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()
Reply
#8
(Oct-02-2020, 11:39 PM)scidam Wrote: I expected that you modify do_GET, but not put it outside
StreamingHandler.
Your StreamingHandler should look like the following:

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

Thank you once again scidam :) Now the code seems to be ok structurally. Unfortunately I still cannot access the xxx/get-temp and/or get the temp reading to show on the page. In the console I have this output when I run the script:

91.155.104.47 - - [03/Oct/2020 10:28:06] "GET /index.html HTTP/1.1" 200 -
91.155.104.47 - - [03/Oct/2020 10:28:06] "GET /stream.mjpg HTTP/1.1" 200 -
91.155.104.47 - - [03/Oct/2020 10:28:06] code 404, message Not Found
91.155.104.47 - - [03/Oct/2020 10:28:06] "GET /favicon.ico HTTP/1.1" 404 -
Here's the complete page after the edits:

# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

import os
import glob
import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
import time
from w1thermsensor import W1ThermSensor
PAGE="""\
<html>
<head>
<title>Kanikamera</title>
<script>
function updateTemp(){
window.fetch('http://your_url/get-temp', {method: 'get'}).then(r => r.json())
  .then(function(data){
   let el = document.getElementById('temperature')
   el.innerHTML = data.stringify() // you can do this better
})
  .catch(e => console.log("error ocurred..."))
}
 
 
// this executes only once, but you need to run it every second
updateTemp() // You probably need to run this continuously, e.g. using SetInterval function
 
</script>

</head>
<body>
<center><h1>Kanikamera</h1></center>
<center><h3>L&auml;mp&ouml;tila</h3><h3 id="portfolio-code"></h3></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
<center><div id="temperature"></div></center>

<!--This is the script for displaying the temperature on the web page-->
</body>
</html>
"""
#This is the part to get the temperature
#os.system('modprscriptobe w1-gpio')
#os.system('modprobe w1-therm')  
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
  
def read_temp_raw():
     f = open(device_file, 'r')
     lines = f.readlines()
     f.close()
     return lines
  
def read_temp():
     lines = read_temp_raw()
     while lines[0].strip()[-3:] != 'YES':
         time.sleep(0.2)
         lines = read_temp_raw()
     equals_pos = lines[1].find('t=')
     if equals_pos != -1:
         temp_string = lines[1][equals_pos+2:]
         temp_c = float(temp_string) / 1000.0
         temp_f = temp_c * 9.0 / 5.0 + 32.0
         return temp_c, temp_f

#This is the part, which makes the endpoint for the AJAX.
    # def do_GET(self):
        # if self.path == '/':
            # self.send_response(301)
            # self.send_header('Location', '/index.html')
            # self.end_headers()
        # elif self.path == '/index.html':
            # content = PAGE.encode('utf-8')
            # self.send_response(200)
            # self.send_header('Content-Type', 'text/html')
            # self.send_header('Content-Length', len(content))
            # self.end_headers()
            # self.wfile.write(content)
        # elif self.path == '/get-temp':
            # self.send_response(200)
            # self.send_header('Content-Type', 'application/json')
            # self.end_headers()
            # tf, tc = read_temp()
            # self.wfile.write(json.dumps({'temp_c':10, 'temp_f':10}))

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()
 
    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

#This is the part for the camera
class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()
class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='1280x720', framerate=24) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    #camera.rotation = 90
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()
Reply
#9
I "replaced" video stream with time.sleep, and tried the following code:

import io, time
import logging
import socketserver
import json
from http import server
 
PAGE="""\
<html>
<head>
<title>Raspberry Pi - Surveillance Camera</title>
</head>
<body>
<center><h1>Raspberry Pi - Surveillance Camera</h1></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
</body>
</html>
"""
 

 
class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            self.wfile.write(json.dumps({'temp_c':12, 'temp_f':12}).encode('utf-8'))
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                time.sleep(1000)
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()
 
class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True
 
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
server.serve_forever()
It works; It continuously serves /stream.mjpg and returns fake temperatures.
Reply
#10
(Oct-03-2020, 09:30 AM)emuola Wrote:
(Oct-02-2020, 11:39 PM)scidam Wrote: I expected that you modify do_GET, but not put it outside
StreamingHandler.
Your StreamingHandler should look like the following:

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

Thank you once again scidam :) Now the code seems to be ok structurally. Unfortunately I still cannot access the xxx/get-temp and/or get the temp reading to show on the page. In the console I have this output when I run the script:

91.155.104.47 - - [03/Oct/2020 10:28:06] "GET /index.html HTTP/1.1" 200 -
91.155.104.47 - - [03/Oct/2020 10:28:06] "GET /stream.mjpg HTTP/1.1" 200 -
91.155.104.47 - - [03/Oct/2020 10:28:06] code 404, message Not Found
91.155.104.47 - - [03/Oct/2020 10:28:06] "GET /favicon.ico HTTP/1.1" 404 -
Here's the complete page after the edits:

# Web streaming example
# Source code from the official PiCamera package
# http://picamera.readthedocs.io/en/latest/recipes2.html#web-streaming

import os
import glob
import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
import time
from w1thermsensor import W1ThermSensor
PAGE="""\
<html>
<head>
<title>Kanikamera</title>
<script>
function updateTemp(){
window.fetch('http://your_url/get-temp', {method: 'get'}).then(r => r.json())
  .then(function(data){
   let el = document.getElementById('temperature')
   el.innerHTML = data.stringify() // you can do this better
})
  .catch(e => console.log("error ocurred..."))
}
 
 
// this executes only once, but you need to run it every second
updateTemp() // You probably need to run this continuously, e.g. using SetInterval function
 
</script>

</head>
<body>
<center><h1>Kanikamera</h1></center>
<center><h3>L&auml;mp&ouml;tila</h3><h3 id="portfolio-code"></h3></center>
<center><img src="stream.mjpg" width="1280" height="720"></center>
<center><div id="temperature"></div></center>

<!--This is the script for displaying the temperature on the web page-->
</body>
</html>
"""
#This is the part to get the temperature
#os.system('modprscriptobe w1-gpio')
#os.system('modprobe w1-therm')  
base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28*')[0]
device_file = device_folder + '/w1_slave'
  
def read_temp_raw():
     f = open(device_file, 'r')
     lines = f.readlines()
     f.close()
     return lines
  
def read_temp():
     lines = read_temp_raw()
     while lines[0].strip()[-3:] != 'YES':
         time.sleep(0.2)
         lines = read_temp_raw()
     equals_pos = lines[1].find('t=')
     if equals_pos != -1:
         temp_string = lines[1][equals_pos+2:]
         temp_c = float(temp_string) / 1000.0
         temp_f = temp_c * 9.0 / 5.0 + 32.0
         return temp_c, temp_f

#This is the part, which makes the endpoint for the AJAX.
    # def do_GET(self):
        # if self.path == '/':
            # self.send_response(301)
            # self.send_header('Location', '/index.html')
            # self.end_headers()
        # elif self.path == '/index.html':
            # content = PAGE.encode('utf-8')
            # self.send_response(200)
            # self.send_header('Content-Type', 'text/html')
            # self.send_header('Content-Length', len(content))
            # self.end_headers()
            # self.wfile.write(content)
        # elif self.path == '/get-temp':
            # self.send_response(200)
            # self.send_header('Content-Type', 'application/json')
            # self.end_headers()
            # tf, tc = read_temp()
            # self.wfile.write(json.dumps({'temp_c':10, 'temp_f':10}))

class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()
 
    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

#This is the part for the camera
class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/get-temp':
            self.send_response(200)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            tf, tc = read_temp()
            self.wfile.write(json.dumps({'temp_c':tf, 'temp_f':tc}))
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()
class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='1280x720', framerate=24) as camera:
    output = StreamingOutput()
    #Uncomment the next line to change your Pi's Camera rotation (in degrees)
    #camera.rotation = 90
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()

Thanks again scidam :) I got the jasonifying working, it displays the fixed temp values :) However, I don't quite follow, what is the purpose of the stream.mjpg? The log shows it's served successfully with status "200" though. Sorry, I'm a noob Wall
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Combining 2 scripts wpothers 5 4,711 Feb-21-2017, 12:38 PM
Last Post: wavic

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020