I am working on a project, to control a RC car with Raspberry Pi and have done it with he help of WeiOPi.
Now I wanted to add a Ultrasonic Range Finder on it (I have HC-SR04).
I googled in internet about it and didn't find much information, I have a question.
How I can combine the python code with java-script and html to print the Distance on the web page.
Thanks in advance,
Any Help will be appreciated.
Regards,
H.M
P.S, I am only 13 and new to Programming.
EDIT:
Unfinished Code:
The python code is:
import webiopi
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
TRIG = 23
ECHO = 24
print "Distance Measurement In Progress"
GPIO.setup(TRIG,GPIO.OUT)
GPIO.setup(ECHO,GPIO.IN)
GPIO.output(TRIG, False)
print "Waiting For Sensor To Settle"
time.sleep(2)
GPIO.output(TRIG, True)
time.sleep(0.00001)
GPIO.output(TRIG, False)
while GPIO.input(ECHO)==0:
pulse_start = time.time()
while GPIO.input(ECHO)==1:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
distance = pulse_duration * 17150
# _____________________________________________________________________
# I want to print the following string (distance) to print on html page
# ---------------------------------------------------------------------
#webiopi.macro
def getSensor(channel):
percent = round(distance, 2)
return "%.2f%%" % percent
#Instantiate the server on the port 8000, it starts immediately in its own thread
server = webiopi.Server(port=8000)
# Run our loop until CTRL-C is pressed or SIGTERM received
webiopi.runLoop()
# -------------------------------------------------- #
# Termination part #
# -------------------------------------------------- #
# Stop the server
server.stop()
The html code:
<script type="text/javascript" src="/webiopi.js"></script>
<script type="text/javascript">
webiopi().ready(init);
// defines function passed previously to webiopi().ready()
function init() {
// automatically refresh UI each seconds
setInterval(updateUI, 1000);
}
// function called through setInterval
function updateUI() {
webiopi().callMacro("getSensor", 0, sensorCallback);
webiopi().callMacro("getSensor", 1, sensorCallback);
webiopi().callMacro("getSensor", 2, sensorCallback);
webiopi().callMacro("getSensor", 3, sensorCallback);
}
// callback function used to display sensor data
function sensorCallback(macroName, channel, data) {
// use jQuery to change spans content
$("#sensor"+channel).text(data);
}
</script>
</head>
<body>
<div align="center">
<div>Sensor 0: <span id="sensor0"></span></div>
<div>Sensor 1: <span id="sensor1"></span></div>
<div>Sensor 2: <span id="sensor2"></span></div>
<div>Sensor 3: <span id="sensor3"></span></div>
</div>
</body>
</html>
Related
i am gettinig this error below when i try to run the second thread on my pico w.
Traceback (most recent call last):
File "<stdin>", line 114, in <module>
OSError: core1 in use
I am trying to display some content in one thread, and in another, server a simple web page with the same content.
"""BME688 / BME680 demo
This demo will work for both the BME680 and BME688.
"""
print("lets import and use the libraries")
import time
from time import sleep
import network
import socket
import _thread
from breakout_bme68x import BreakoutBME68X, STATUS_HEATER_STABLE
from pimoroni_i2c import PimoroniI2C
from picographics import PicoGraphics, DISPLAY_LCD_240X240, PEN_P8
display = PicoGraphics(display=DISPLAY_LCD_240X240, pen_type=PEN_P8)
display.set_backlight(1.0)
WIDTH, HEIGHT = display.get_bounds()
ssid = 'netgear_2.4g' #Your network name
password = '9xc4prce' #Your WiFi password
print("setting pin breakouts etc")
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
print("finish setting pins and now set i2c")
i2c = PimoroniI2C(**PINS_BREAKOUT_GARDEN)
print("i2c set and now set bme")
bme = BreakoutBME68X(i2c)
print("bme set")
# If this gives an error, try the alternative address
# bme = BreakoutBME68X(i2c, 0x77)
temperatureReadingData = ["","0.0c"]
print("Testing sensors on the while loop")
def connect():
#Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while wlan.isconnected() == False:
print('Waiting for connection...')
sleep(1)
ip = wlan.ifconfig()[0]
print(f'Connected on {ip}')
return ip
def open_socket(ip):
# Open a socket
address = (ip, 80)
connection = socket.socket()
connection.bind(address)
connection.listen(1)
return connection
def readTemperature():
temperature, pressure, humidity, gas, status, _, _ = bme.read()
heater = "Stable" if status & STATUS_HEATER_STABLE else "Unstable"
temperatureReadingData[0] = "Temperature is {:0.2f}c, Pressure is {:0.2f}Pa, humidity is {:0.2f}%, gas is {:0.2f} Ohms, Heater: {}".format(temperature, pressure, humidity, gas, heater)
temperatureReadingData[1] = "{:0.2f}c".format(temperature)
def webpage(reading):
#Template HTML
html = f"""
<!DOCTYPE html>
<html>
<head>
<title>Pico W Weather Station</title>
<meta http-equiv="refresh" content="10">
</head>
<body>
<p>{reading}</p>
</body>
</html>
"""
return str(html)
def serve():
#Start a web server
ip = connect()
connection = open_socket(ip)
while True:
client = connection.accept()[0]
request = client.recv(1024)
request = str(request)
html = webpage(temperatureReadingData[0])
client.send(html)
client.close()
def displayTemp():
while True:
readTemperature()
print("display temp" + temperatureReadingData[1])
display.clear()
display.set_pen(15)
display.text(temperatureReadingData[1], 0, 0, scale=4)
display.update()
time.sleep(1.0)
if __name__ == "__main__":
try:
tempDisplay = _thread.start_new_thread(displayTemp, ())
webServer = _thread.start_new_thread(serve, ())
except KeyboardInterrupt:
machine.reset()
I'm new to flask world and wondering what causes the program to fail. every time i run my app i'm getting interfaceError. i was able to print the data on command line but this error displayed when i'm trying to render on html. thank you so much for your help
here is my mainApp.py file
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
from models import People, db
from flask_migrate import Migrate
import psycopg2
# creates an application that is named after the name of the file
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = "postgresql://student_user:1234#localhost:5432/studentdb"
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
migrate = Migrate(app, db)
#conn = "postgresql://student_user:1234#localhost:5432/studentdb"
conn = psycopg2.connect(dbname="teacherdb", host="localhost", user="teacher_user", password=1234)
cur = conn.cursor()
#app.route('/')
def index():
# Execute a query
cur.execute("SELECT * FROM teachertb")
# Retrieve query results
records = cur.fetchall()
print(records)
conn.close()
return render_template("index.html", records=records)
if __name__ == "__main__":
app.run(debug=True)
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
{% for record in range(0, len(records)) %}
<p>{{ records[record][1] }}</p>
{% endfor %}
</body>
</html>
Lastly, if name == "main": checks that the current file is being run as the main program and calls app.run(debug=True) to start the application with the debug mode enabled.
Please note that the configuration of the database(like user name,password,host) may have to be updated accordingly. It also seems like the connection is closed before sending the records variable to the template, which may cause the program to not work properly.
So, im trying to make a webserver and processing data with a pico in parallel, my goal is to reach the pico from my browser using the local network ip to see in what step the pico is working and what data is on the current loop, however i have two issues and i have no idea how to make it work:
When running the two process in parallel using _thread, the webserver function hangs until the dataprocess function finish, so i cant see in realtime what is going on, the webserver respond only when the other process is finished and it hangs again, i need to press f5 on my browser at the exact time when the dataprocess function finish and start again only to see part of the process because it hangs if i refresh my browser to see the progress
When running the webserver, the urequets.get function of the dataprocess function does not work, it throws [Errno 103] ECONNABORTED
Here is the part of my code that is not working:
import utime, machine, urequests, json, network, socket, _thread
led = machine.Pin("LED", machine.Pin.OUT)
def connect():
global wlan
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("SSID", "PASSS")
while wlan.isconnected() == False:
print("Connecting...")
led.off()
utime.sleep_ms(100)
led.on()
utime.sleep_ms(100)
led.off()
utime.sleep_ms(100)
led.on()
utime.sleep_ms(100)
led.on()
ip = wlan.ifconfig()[0]
print(f'Connected on {ip}')
return ip
def open_socket(ip):
address = (ip, 80)
connection = socket.socket()
connection.bind(address)
connection.listen(1)
return connection
def webpage(steps):
html = f"""
<!DOCTYPE html>
<html>
<head>
<title>Pico 2</title>
</head>
<body>
<p>{steps}</p>
</body>
</html>
"""
return str(html)
def pushgetdata():
while wlan.isconnected() == True:
try:
global steps
led.off()
utime.sleep_ms(300)
led.on()
steps = "Step 1: Reading values from sensor one...<br>"
#function to read data from one sensor here
#...
#...
#...
led.off()
utime.sleep_ms(100)
led.on()
steps = steps + "Step 2: Reading values from sensor two...<br>"
#function to read data from other sensor here
#...
#...
#...
led.off()
utime.sleep_ms(100)
led.on()
steps = steps + "Step 3: Pushing and getting results...<br>"
jsondata = urequests.get("https://xxx.xxx.xxx/api/?device=pico2&sensor1=valulesfromsensor1&sensor2=valuesfromsensor2")
proceseddata = jsondata.json()
steps = steps + proceseddata + "<br>"
steps = steps + "Step 4: Doing things with results...<br>"
#function to do conditions and things with results...
#...
#...
#...
jsondata.close()
steps = steps + "Step 5: Finished, sleeping for the next round...<br>"
utime.sleep_ms(100)
led.off()
utime.sleep_ms(100)
led.on()
utime.sleep(900)
except OSError as e:
steps = steps + e
def serve(connection):
while True:
try:
client, addr = connection.accept()
print('client connected from', addr)
request = client.recv(1024)
request = str(request)
html = webpage(steps)
client.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
client.send(html)
client.close()
except OSError as e:
client.close()
def webserver():
ip = connect()
connection = open_socket(ip)
_thread.start_new_thread(serve,(connection,))
try:
webserver()
pushgetdata()
except KeyboardInterrupt:
machine.reset()
I'm not sure exactly what's going on with your code, but using the same threading idea, please find here my solution for a similar problem I've encountered today if it helps.
from machine import Pin
from time import sleep
import wlan_data, network
import socket, _thread
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(wlan_data.SSID, wlan_data.PASSWORD)
print("WLAN is connected: " + str(wlan.isconnected()))
page = open("index.html", "r")
html = page.read()
page.close()
sta_if = network.WLAN(network.STA_IF)
print(sta_if.ifconfig()[0])
def setUpSocket():
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(addr)
s.listen(1)
return s
def serve(s):
while True:
try:
cl, addr = s.accept()
cl_file = cl.makefile('rwb', 0)
while True:
line = cl_file.readline()
if not line or line == b'\r\n':
break
response = html
cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
cl.send(response)
cl.close()
except OSError as e:
cl.close()
def webserver():
s = setUpSocket()
_thread.start_new_thread(serve,(s,))
webserver()
led = machine.Pin("LED", machine.Pin.OUT)
led.toggle()
while 1:
led.toggle()
sleep(10)
_thread library is experimental and buggy. From the micropython documentation https://docs.micropython.org/en/latest/library/_thread.html
This module is highly experimental and its API is not yet fully settled and not yet described in this documentation.
From my own testing, some of the functionality works for a while, then you might add another import and things stop working. Best to steer clear until it is no longer an experimental feature.
I have an issue with running part of a code to be more specific defined as new thread CoreTask().
I have no idea why I cannot turn on/off built-in LED. The rest of the code looks to be working as expected (WIFI integration and 'httpd service' work fine).
I use Raspberry Pi Pico W with latest MicroPython loaded.
Please advice... Thanks!
import machine
import _thread
import network
import socket
import utime
from machine import Pin
led = machine.Pin('LED', machine.Pin.OUT)
ssid = 'someSSID'
password = 'somePASSWORD'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
html = """<!DOCTYPE html>
<html>
<body>
<div id="humidity">100</div>
<div id="temperature">21</div>
</body>
</html>
"""
sLock = _thread.allocate_lock()
def CoreTask():
while True:
sLock.acquire()
print('LED...')
led.on()
utime.sleep(1)
led.off()
utime.sleep(1)
sLock.release()
_thread.start_new_thread(CoreTask, ())
while True:
sLock.acquire()
# Wait for connect or fail
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print('waiting for connection...')
utime.sleep(1)
# Handle connection error
if wlan.status() != 3:
raise RuntimeError('network connection failed')
else:
print('connected')
status = wlan.ifconfig()
print( 'ip = ' + status[0] )
# Open socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print('listening on', addr)
# Listen for connections
while True:
try:
cl, addr = s.accept()
print('client connected from', addr)
request = cl.recv(1024)
print(request)
request = str(request)
response = html
cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
cl.send(response)
cl.close()
except OSError as e:
cl.close()
print('connection closed')
sLock.release()
I'm also keen to know a solution, so far the best try I have got the onboard led working in seperate thread is the following simple code, every other more complicated try was failed.
I have only tested this with onboard LED, so if anyone may try if threading works on real GPIO? If it does, I think this is not an issue as most of time we send out "status blinks" on other LED in project not the onboard one.
import machine
import _thread
import time
def led():
led = machine.Pin('LED', machine.Pin.OUT)
while True:
led.on()
time.sleep(.5)
led.off()
time.sleep(.5)
def pnt():
i=0
while True:
i += 1
print(f"\rThis is the {i} cycle......", sep="", end="")
time.sleep(1)
if __name__ == "__main__":
th1 = _thread.start_new_thread(pnt, ())
#th2 = _thread.start_new_thread(led, ()) This line did not work
led()
I think someone said in a video that the threading is still in experiment and has problems on pico w, and they are working on it.
I also could not workout how to achieve same result with uasycncio, it looks like calling the LED to blink is not about programming but real physical movement, so cannot be "await". Can anyone show ma a correct way?
It's is such an important function to waiting for program (connection loop) while sending "status blinks"
Trying to create a web-front end for a Python3 backed application. The application will require bi-directional streaming which sounded like a good opportunity to look into websockets.
My first inclination was to use something already existing, and the example applications from mod-pywebsocket have proved valuable. Unfortunately their API doesn't appear to easily lend itself to extension, and it is Python2.
Looking around the blogosphere many people have written their own websocket server for earlier versions of the websocket protocol, most don't implement the security key hash so dont' work.
Reading RFC 6455 I decided to take a stab at it myself and came up with the following:
#!/usr/bin/env python3
"""
A partial implementation of RFC 6455
http://tools.ietf.org/pdf/rfc6455.pdf
Brian Thorne 2012
"""
import socket
import threading
import time
import base64
import hashlib
def calculate_websocket_hash(key):
magic_websocket_string = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
result_string = key + magic_websocket_string
sha1_digest = hashlib.sha1(result_string).digest()
response_data = base64.encodestring(sha1_digest)
response_string = response_data.decode('utf8')
return response_string
def is_bit_set(int_type, offset):
mask = 1 << offset
return not 0 == (int_type & mask)
def set_bit(int_type, offset):
return int_type | (1 << offset)
def bytes_to_int(data):
# note big-endian is the standard network byte order
return int.from_bytes(data, byteorder='big')
def pack(data):
"""pack bytes for sending to client"""
frame_head = bytearray(2)
# set final fragment
frame_head[0] = set_bit(frame_head[0], 7)
# set opcode 1 = text
frame_head[0] = set_bit(frame_head[0], 0)
# payload length
assert len(data) < 126, "haven't implemented that yet"
frame_head[1] = len(data)
# add data
frame = frame_head + data.encode('utf-8')
print(list(hex(b) for b in frame))
return frame
def receive(s):
"""receive data from client"""
# read the first two bytes
frame_head = s.recv(2)
# very first bit indicates if this is the final fragment
print("final fragment: ", is_bit_set(frame_head[0], 7))
# bits 4-7 are the opcode (0x01 -> text)
print("opcode: ", frame_head[0] & 0x0f)
# mask bit, from client will ALWAYS be 1
assert is_bit_set(frame_head[1], 7)
# length of payload
# 7 bits, or 7 bits + 16 bits, or 7 bits + 64 bits
payload_length = frame_head[1] & 0x7F
if payload_length == 126:
raw = s.recv(2)
payload_length = bytes_to_int(raw)
elif payload_length == 127:
raw = s.recv(8)
payload_length = bytes_to_int(raw)
print('Payload is {} bytes'.format(payload_length))
"""masking key
All frames sent from the client to the server are masked by a
32-bit nounce value that is contained within the frame
"""
masking_key = s.recv(4)
print("mask: ", masking_key, bytes_to_int(masking_key))
# finally get the payload data:
masked_data_in = s.recv(payload_length)
data = bytearray(payload_length)
# The ith byte is the XOR of byte i of the data with
# masking_key[i % 4]
for i, b in enumerate(masked_data_in):
data[i] = b ^ masking_key[i%4]
return data
def handle(s):
client_request = s.recv(4096)
# get to the key
for line in client_request.splitlines():
if b'Sec-WebSocket-Key:' in line:
key = line.split(b': ')[1]
break
response_string = calculate_websocket_hash(key)
header = '''HTTP/1.1 101 Switching Protocols\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Accept: {}\r
\r
'''.format(response_string)
s.send(header.encode())
# this works
print(receive(s))
# this doesn't
s.send(pack('Hello'))
s.close()
s = socket.socket( socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 9876))
s.listen(1)
while True:
t,_ = s.accept()
threading.Thread(target=handle, args = (t,)).start()
Using this basic test page (which works with mod-pywebsocket):
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Web Socket Example</title>
<meta charset="UTF-8">
</head>
<body>
<div id="serveroutput"></div>
<form id="form">
<input type="text" value="Hello World!" id="msg" />
<input type="submit" value="Send" onclick="sendMsg()" />
</form>
<script>
var form = document.getElementById('form');
var msg = document.getElementById('msg');
var output = document.getElementById('serveroutput');
var s = new WebSocket("ws://"+window.location.hostname+":9876");
s.onopen = function(e) {
console.log("opened");
out('Connected.');
}
s.onclose = function(e) {
console.log("closed");
out('Connection closed.');
}
s.onmessage = function(e) {
console.log("got: " + e.data);
out(e.data);
}
form.onsubmit = function(e) {
e.preventDefault();
msg.value = '';
window.scrollTop = window.scrollHeight;
}
function sendMsg() {
s.send(msg.value);
}
function out(text) {
var el = document.createElement('p');
el.innerHTML = text;
output.appendChild(el);
}
msg.focus();
</script>
</body>
</html>
This receives data and demasks it correctly, but I can't get the transmit path to work.
As a test to write "Hello" to the socket, the program above calculates the bytes to be written to the socket as:
['0x81', '0x5', '0x48', '0x65', '0x6c', '0x6c', '0x6f']
Which match the hex values given in section 5.7 of the RFC. Unfortunately the frame never shows up in Chrome's Developer Tools.
Any idea what I'm missing? Or a currently working Python3 websocket example?
When I try talking to your python code from Safari 6.0.1 on Lion I get
Unexpected LF in Value at ...
in the Javascript console. I also get an IndexError exception from the Python code.
When I talk to your python code from Chrome Version 24.0.1290.1 dev on Lion I don't get any Javascript errors. In your javascript the onopen() and onclose() methods are called, but not the onmessage(). The python code doesn't throw any exceptions and appears to have receive message and sent it's response, i.e exactly the behavior your seeing.
Since Safari didn't like the trailing LF in your header I tried removing it, i.e
header = '''HTTP/1.1 101 Switching Protocols\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Accept: {}\r
'''.format(response_string)
When I make this change Chrome is able to see your response message i.e
got: Hello
shows up in the javascript console.
Safari still doesn't work. Now it raise's a different issue when I attempt to send a message.
websocket.html:36 INVALID_STATE_ERR: DOM Exception 11: An attempt was made to use an object that is not, or is no longer, usable.
None of the javascript websocket event handlers ever fire and I'm still seeing the IndexError exception from python.
In conclusion. Your Python code wasn't working with Chrome because of an extra LF in your header response. There's still something else going on because the code the works with Chrome doesn't work with Safari.
Update
I've worked out the underlying issue and now have the example working in Safari and Chrome.
base64.encodestring() always adds a trailing \n to it's return. This is the source of the LF that Safari was complaining about.
call .strip() on the return value of calculate_websocket_hash and using your original header template works correctly on Safari and Chrome.