Python Forum
sending data to second python script
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
sending data to second python script
#1
Hi everyone,

I am trying to learn a bit of python and picked up a little project to give the coding a purpose. I am trying to make a temperature stabilized water bath using a temperature sensor, a heater and a raspberry pi (and some more stuff, like an oled display and a rotary encoder). I tried out bokeh to create a web interface and everything was going pretty ok until I asked my girlfriend to take a look on her phone while I had the web interface open on my pc. She opened the url that runs the python script and caused all kinds of errors because she was initializing all the hardware again. My mistake was to not separate the hardware controlling part of the script from the data visualization. If I could use bokeh to just run a script that plots the data and gets fed the temperature readings from the hardware controlling script it could be run as many times as it needs to be. I would run the hardware script and one plotting script as the pi starts up. As more people look at the url the plotting part gets executed multiple times, but the hardware script keeps being the only instance.

I have no idea how to do that, though. I looked at nmap and subprocess, but I don't really get it. My data is currently a dictionary, but I am not necessarily insisting on that...

Could be that there are other solutions to my problem as well... Maybe bokeh can be configured/run in a way that just shows the same thing to multiple users and is not running the script again. Maybe there is a clever way to do what I want to do from a single script without running into problems. I am happy with any solution, but I thought the piping of data from one script to another could be an interesting thing to learn as well.

import RPi.GPIO as GPIO
from threading import Lock, Thread
from functools import partial
from concurrent.futures import ThreadPoolExecutor
from time import sleep, time
from bokeh.layouts import column
from bokeh.models import ColumnDataSource
from bokeh.document import without_document_lock
from bokeh.plotting import figure, curdoc
import Adafruit_MCP9808.MCP9808 as MCP9808
from PID import PID
from tornado import gen
from TempDisp import TempDisp

				# GPIO Ports
Enc_A = 27              # Encoder input A: input GPIO 4 
Enc_B = 17                   # Encoder input B: input GPIO 14 
button = 18
SSR = 26
Rotary_counter = 0           # Start counting from 0
Current_A = 1               # Assume that rotary switch is not 
Current_B = 1               # moving while we init software
running = False
pwm_frequency = 100
t0 = time()
tsens = MCP9808.MCP9808()
P = 20
I = 0
D = 0
pid = PID(P,I,D)
pid.SetPoint = 0
pid.setSampleTime = 0.2
disp = TempDisp()
LockRotary = Lock()      # create lock for rotary switch
executor = ThreadPoolExecutor(max_workers=2)

def start_stop_pwm(channel):  
	global pwm, running, pidOut	
	if running == True:
		pwm.stop()
		running = False
	else:
		pwm.start(pidOut)
		running = True 
 
# initialize interrupt handlers
def init():
	GPIO.setwarnings(True)
	GPIO.setmode(GPIO.BCM)				# I used BOARD (not BCM) mode, but that was causing problems with the oled library
								# define the Encoder switch inputs
	GPIO.setup(SSR,GPIO.OUT)
	GPIO.setup(Enc_A, GPIO.IN, pull_up_down = GPIO.PUD_UP)             
	GPIO.setup(Enc_B, GPIO.IN, pull_up_down = GPIO.PUD_UP)
	GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_UP) #define "button" pin as input and set up internal pullup resis$
	
					# setup callback thread for the A and B encoder 
					# use interrupts for all inputs
	GPIO.add_event_detect(Enc_A, GPIO.RISING, callback=rotary_interrupt)             # NO bouncetime 
	GPIO.add_event_detect(Enc_B, GPIO.RISING, callback=rotary_interrupt)             # NO bouncetime
	GPIO.add_event_detect(button, GPIO.FALLING, callback=start_stop_pwm, bouncetime=200)
	tsens.begin()
	return



# Rotarty encoder interrupt:
# this one is called for both inputs from rotary switch (A and B)
def rotary_interrupt(A_or_B):
	global Rotary_counter, Current_A, Current_B, LockRotary
                                       # read both of the switches
	Switch_A = GPIO.input(Enc_A)
	Switch_B = GPIO.input(Enc_B)
                                       # now check if state of A or B has changed
                                       # if not that means that bouncing caused it
	if Current_A == Switch_A and Current_B == Switch_B:      # Same interrupt as before (Bouncing)?
		return                              # ignore interrupt!

	Current_A = Switch_A                        # remember new state
	Current_B = Switch_B                        # for next bouncing check


	if (Switch_A and Switch_B):                  # Both one active? Yes -> end of sequence
		LockRotary.acquire()                  # get lock 
		if A_or_B == Enc_B:                     # Turning direction depends on 
			Rotary_counter += 1                  # which input gave last interrupt
		else:                              # so depending on direction either
			Rotary_counter -= 1                  # increase or decrease counter
		LockRotary.release()                  # and release lock
	return                                 # THAT'S IT

doc = curdoc()

@gen.coroutine
def update_data(x,y1,y2):
	new_data=dict(t = [x], tarTemp = [y1], temp = [y2])
	data.stream(new_data, 10000)
# Main loop. Demonstrate reading, direction and speed of turning left/rignt

@gen.coroutine
@without_document_lock
def main():
	global tarTemp, pwm, Rotary_counter, LockRotary, SSR, pwm_frequency, t0, tsens, pid, pidOut
	pidOut = 0	
	tarTemp = 0                           # Current tarTemp   
	NewCounter = 0                        # for faster reading with locks
	
	init()                              # Init interrupts, GPIO, ...
	pwm = GPIO.PWM(SSR,pwm_frequency) #allows pwm.start(DutyCycle) followed by pwm.ChangeDutyCycle(DutyCycle) and pwm.ChangeFrequency(pwm_frequency)
	try:
		while True :                        # start test 
			sleep(0.2)                        # sleep 200 msec

									# because of threading make sure no thread
									# changes value until we get them
									# and reset them

			LockRotary.acquire()               # get lock for rotary switch
			NewCounter = Rotary_counter         # get counter value
			Rotary_counter = 0                  # RESET IT TO 0
			LockRotary.release()               # and release lock
               
			if (NewCounter !=0):               # Counter has CHANGED
				tarTemp = tarTemp + NewCounter*abs(NewCounter)   # Decrease or increase tarTemp 
				if tarTemp < 0:                  # limit tarTemp to 0...100
					tarTemp = 0
				elif tarTemp > 100:               # limit tarTemp to 0...100
					tarTemp = 100
				pid.SetPoint = tarTemp
				pidOut=pid.output	# !!! MAPPING NEEDS FIXING !!!
				if pidOut > 100:
					pidOut = 100
				elif pidOut < 0:
					pidOut = 0
				print(pid.output,pidOut)
				pwm.ChangeDutyCycle(pidOut)
			
			newT = tsens.readTempC()
			newTemp = round(newT,1)
			disp.Display(tarTemp,newTemp)
			pid.update(newTemp)
			doc.add_next_tick_callback(partial(update_data, x=time()-t0, y1=tarTemp, y2=newTemp))
		 
	except KeyboardInterrupt:
		print('interrupted with keyboard')
	except:
		print('unspecified error')
	finally:
		GPIO.cleanup()

data=ColumnDataSource(dict(t=[], tarTemp=[], temp=[]))
fig=figure(logo=None)
fig.xaxis.axis_label = 'Time (s)'
fig.line(source=data, x='t', y='tarTemp', line_width=2, alpha=.85, color='pink')
fig.line(source=data, x='t', y='temp', line_width=2, alpha=.85, color='purple')
	

doc.add_root(fig)
thread = Thread(target=main)
thread.start()
Lots of this code is copy pasted from solutions I found on the internet. I am not claiming that any of this is my intellectual property.
Reply
#2
I stripped some unnecessary stuff from the example to make it easier to follow. I will have another look at whether it can be stripped down even more (the tornado and thread stuff), but I tested it like this and it runs from my pi (which is good).

import random
from time import sleep, time
from tornado import gen
from functools import partial
from concurrent.futures import ThreadPoolExecutor
from threading import Lock, Thread

from bokeh.layouts import column
from bokeh.models import ColumnDataSource
from bokeh.document import without_document_lock
from bokeh.plotting import figure, curdoc

t0=time()

executor = ThreadPoolExecutor(max_workers=2)
doc = curdoc()
@gen.coroutine
def update_data(x,y1,y2):
	new_data=dict(t = [x], tarTemp = [y1], temp = [y2])
	data.stream(new_data, 10000)


@gen.coroutine
@without_document_lock
def main():
	while True:
		doc.add_next_tick_callback(partial(update_data, x=time()-t0, y1=random.randint(0,100), y2=random.randint(0,100)))
		sleep(1)


data=ColumnDataSource(dict(t=[], tarTemp=[], temp=[]))
fig=figure(logo=None)
fig.xaxis.axis_label = 'Time (s)'
fig.line(source=data, x='t', y='tarTemp', line_width=2, alpha=.85, color='pink')
fig.line(source=data, x='t', y='temp', line_width=2, alpha=.85, color='purple')


doc.add_root(fig)
thread = Thread(target=main)
thread.start()
# start from console with	bokeh serve bokehtest.py --allow-websocket-origin=yourIP:5006
# and use a browser to look at yourIP:5006
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Sending data from the form to DB quisatz 6 1,242 Nov-13-2023, 09:23 AM
Last Post: Annaat20
  Is there a *.bat DOS batch script to *.py Python Script converter? pstein 3 3,009 Jun-29-2023, 11:57 AM
Last Post: gologica
  How to modify python script to append data on file using sql server 2019? ahmedbarbary 1 1,177 Aug-03-2022, 06:03 AM
Last Post: Pedroski55
  Help Sending Socket Data snippyro 0 1,014 Sep-23-2021, 01:52 AM
Last Post: snippyro
  Sending string commands from Python to a bluetooth device Rovelin 13 9,283 Aug-31-2021, 06:40 PM
Last Post: deanhystad
  get data (temperature and humidity) from DHT22 into CSV and sending them over the net apollo 0 3,797 Apr-16-2021, 07:49 PM
Last Post: apollo
  Refresh data in python script while running in Terminal frankenchrist 4 7,105 Feb-03-2021, 09:54 AM
Last Post: Larz60+
  Sending Out Email via Python JoeDainton123 1 4,701 Aug-31-2020, 12:54 AM
Last Post: nilamo
  How to kill a bash script running as root from a python script? jc_lafleur 4 5,792 Jun-26-2020, 10:50 PM
Last Post: jc_lafleur
  crontab on RHEL7 not calling python script wrapped in shell script benthomson 1 2,248 May-28-2020, 05:27 PM
Last Post: micseydel

Forum Jump:

User Panel Messages

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