Articles Hierarchy

Articles Home » RPI » RPI python flask blog / CMS, GPIO and Arduino uPCS

RPI python flask blog / CMS, GPIO and Arduino uPCS

The MAKER Blog
intro:
here i tested about showing a web-page made with python flask ( a web-server what needs NO installation )
online by the tools ?tunnel? of dataplicity. but i had the idea to use instead the flask example mini-blog "flaskr"
with a sweet layout like from html5up


Blog
Gallery
GPIO
Arduino Firmata ( remote IO )
Arduino PID,IND,DCD with JSON readable protocol
test socket IO


Blog
well, the HTML template works with all the internal links.., even without server just by opening the index.html in a browser.
once you try in flask you have to do it all again! lots of footwork.
also the blog example ( with add entries to a sqlite3 database file... ) has its limits,
i found later examples with entry edit delete... what show that that is much more complicated, close to the php / sql work i did years ago. so i found my own way ( using url line ).


the template has a nice footer with email and social linking
it even has a help page called elements just to show you the CSS-formatting.
you can disable it from the menu later.






- - HELP ( old, not updated pictures )





slowly i want to fill it more.
+ the social network links are easy from the HTML side, but you need twitter facebook ... accounts,
so what i did i used the links from the raspberry pi foundation to show how it is done.
+ the email entry form
the basic way is the mailto: trick, a browser built in, that starts your own email software on your computer ( outlook.. )
and i found hundreds of examples how that URL line is build up, but none how to fill the variables,
so i needed to make my own 2 step:
-a- prepare a setting for a fix email address ( what later must be your SITE EMAIL )
and a fix subject so you can identify the email easily .
-b- read the reader input for
- name
- email ( send a copy to cc )
- message
and prepares the line for the email call:
Send email from your computer

but for the idea that the python / server side / sends a email need to install python email...
i will try later..


Gallery
just included a new /menu/ page, a basic gallery
configuration manually in flask_app.py
gallerylist=[
{'pic':'balloon.jpg','rem':'nice balloon'},
{'pic':'gliders.jpg','rem':'nice gliders'}
]



and a SITE SETUP database driven for some SITE variables, incl. user and password where password now is encrypted.



one of the essential features of a CMS is that you can / need to backup the database,
like to bring your work to a new release of the blog software... ( as long the database structure did not change )
so now is a new button ( at top of the setup page ) BACKUP
making a sql file at
/myblog/static/data/Backup_schema.sql (ups: by root? )
pls find iterdump() at SQlite3

with the |safe switch the (in and ) output of HTML is enabled.
{{ entry.entry|safe }}


but you have to write it in HTML.
now i try to install a BB Code editor like tinyMCA
the new ONLINE version says: This domain is not registered with TinyMCE Cloud. Get a free API key to disable this message

and rearrange the main - detail page



file uploading for pictures in the blog see here
see the full menu tree

the upload page ( where you can browse your local computer for a picture file )

the Blog Edit window and the tinyMCE [image icon]

and the final blog detail page

you link the (uploaded) pictures in the blog by the [image icon]
and the location:
../static/images/picturename.jpg
yes, would be nice if you actually can look into the picture directory ( for upload )




also for a smarter gallery configuration ( by option click?)
that is not easy for me,
lists, arrays and especially dict .. between python and flask html i not understand.
so possibly my way is very stupid,
-a- i have a function what returns a list of existing pictures
{'pic1.jpg','pic2.jpg','pic3.jpg'}
-b- i have the database with the configured pictures for the gallery ( read from database )
[{'pic':'pic2.jpg,'rem':'nice picture'},{'pic':'pic3.jpg,'rem':'also nice picture'}]
-c- for the HTML i need a list what combines both ( but checks the different content )
i use
allpics=[{'pic':'gliders.jpg','rem':'nice gliders','sel':'checked'} ]
allpics.clear()
to create the array
in a FOR loop over all existing pictures i append them
allpics.append({'pic':existingpics[index],'rem':galrem,'sel':galsel})
where in a second ( inner ) FOR loop i check if the picture is in the gallery list and get the rem field.
for the HTML i use a column 'sel' with the content 'checked' or 'unchecked'
sadly HTML not understand this in the checkbox syntax.
so i must make in the HTML form a case depending on it:
{% for entry in allpics %}
{% if (entry.sel == "checked") %}
input: type="checkbox" checked
textarea {{ entry.rem }}

{% else %}
input: type="checkbox"
{% endif %}
{% else %}
{% endfor %}


also the read back of the changes are tricky, possibly not fully tested,
i needed a 2 step thing, first you select a unselected picture for the gallery by click ( and see the check mark )
then SUBMIT ( and the whole thing is called again )
and now see the rem entry field you can edit
( and also edit the rem's of other pictures )
and SUBMIT again.


i made a 'start' file and a 'myblog.desktop' file,
for functioning they need the path of YOUR installation.
so i moved them to /tools/ and renamed them x.template
now you can after extracting the archive do a
./install.sh
what creates a 'start' file there and a .desktop file at your Desktop
( it not creates a Desktop menu entry and not makes a server auto start at boot ( much too early for that )
that was the rev. 0.8.7


GPIO
that's a good status and the BLOG thing is finished,
( to work more i enabled DEBUG again, )
replaced the ONLINE tiny MCE by the downloaded, so the pack is much bigger now.
( make a extra header for that 2 textarea input HTML pages )
+ and start with some new add-ons:
why would we use a raspberry SBC if not for learning,
and a major play field is the physical computing, combine the uPC with your own hardware / electronics.
so as we have already a web-server in Python running ( incl. admin structure what can be used for public view of I/O and action ( drive outputs ...) restricted to admin rights.
i now want connect the GPIO of the raspberry pi into a web page of this blog.
readback of inputs and outputs:

i think you know the html work about table.. but not worry, if you want to change that list of IO, see
rpi_gpio.py# use BCM
in_chan_list = [17,27,22]
out_chan_list = [23,24,25]

channel setup (like digital input with pull-up resistor (PB to GROUND), digital output with initial LOW ),
the scan of the channels
and web page generation is fully automated.
if login can change / toggle outputs



Arduino Firmata ( remote IO )
the next logical step would be the preparation of pages for so called "hat"s
but i not use GPIO so i leave that to YOU.
what i am interested in is the Arduino connection, example:
-+a- Arduino UNO on USB cable
-+b- installed arduino IDE on RPI
-+c- download FIRMATA to Arduino
-+d- RPI python use py firmata
-+e- integration / operation of Arduino "remote" I/O in web page same like above RPI GPIO


-+a- Arduino UNO on USB cable
a arduino need 20 ..50mA if no other hardware is connected
the USB port from RPI could max give 500mA ( if the RPI power supply big enough )
so i use a arduino with USB cable to RPI and all is setup.
-+b- installed arduino IDE on RPI
sudo apt-get install -y arduino
if you need the newest IDE
and look for Linux ARM
also possible:
wget https://downloads.arduino.cc/arduino-nightly-linuxarm.tar.xz
tar xvJf arduino-nightly-linuxarm.tar.xz
cd arduino-nightly
./install.sh

besides that JUST NOW ( 10.3.2017 ) there ( the nightly) has a BUG what not give you menu and desktop icon see here.
-+c- download FIRMATA to Arduino
start IDE and select BOARD and PORT
find example firmata standard firmata and download to arduinio


-+d- RPI python use py firmata
you need to install python firmata lib:
sudo pip3 install pyfirmata as we use python3
and start a python(3) IDLE using
from pyfirmata import Arduino, util
board = Arduino('/dev/ttyACM0')

-+e- integration / operation of Arduino "remote" I/O in web page same like above RPI GPIO
starting with just the digital outputs and using the LED 13 as most easy to check

rpi_arduino.pyDout_chan_list = [4,13]
Din_chan_list = [8,12]
Aout_chan_list = [3,5] # D out PWM UNO: 3,5,6,9,10,11
Ain_chan_list = [0,1] # A in UNO: 0 .. 5

one of the first big differences ( to GPIO lib ) seems to be that there is no OUTPUT READ BACK by firmata?? so i make a set / reset instead of a toggle code.
and the reading of values is more a ENABLE REPORTING what will make the arduino to send the data continuously / until USB port is blocked?? so set a output seems the easy part of it. also see here
still issues about the init,
i now setup firmata with channel setup and start iterator and enable reporting ( for the analog channels only) at first start of the arduino HTML page.
currently not disable reporting so it will fail from USB side??
i tried enable / read / disable, even with wait timer, but never see data, only 'NONE'
still need to update the page to get the first readings.
ok, use a 10s auto-refresh in HTML header. But that makes the problem with the ?missing? output status even bigger. So if i can not read-back outputs i need local memory of settings ( of outputs )
rewrite the whole IO array thing with file storage in RAM Disk, using
import pickle
# after setup done:
with open("/run/shm/readIO.dat","wb") as f:
. pickle.dump(readIO, f)
or
# if file exists no setup needed
if (os.path.isfile("/run/shm/readIO.dat")):
. with open("/run/shm/readIO.dat","rb") as f:
. . readIO = pickle.load(f)

now i can use that array also to store set / setpoints ( written to arduino ) inbetween the HTML calls
but the init problem still exists:
at reboot RPI ( what power cycles the USB .. Arduino ) all works,
but if i restart the server, output works, inputs not get!, and python flask HTML call not know about this, and the ram disk file still exists like at every succeeding call, means i not do a init, the arduino firmata status ( change by server restart ) is not clear for me.
latest look:



update HELP page and
as i now have 3 different headers
-1- normal
-2- start with MCE
-3- auto update 10sec for RPI GPIO / RPI ARDUINO page
i extract the MENU to a external menu.html.
+ + add the [EDIT] icon to the detail page ( if logged in )


Arduino PID,IND,DCD with JSON readable protocol
- - uPCS2 (web) - -
so not happy with the FIRMATA libs on both sides i would like to develop my own ( slow but readable ) communication, in a style i have seen from a NODE project ( JSON.. )
similar to the records used here in / between FLASK and HTML.
starting with a SPEC and a Arduino COM TEST sketch find here


But the biggest difference to my prior python desktop programs is, that this FLASK python webserver creates a HTML web page: and now i will need to show the FACEPLATE in HTML.. and not python TK...
// EXAMPLE OLD PROJECT //

so, i will have fun to make again a PID FACEPLATE but in HTML CSS jquery? animated SVG?
a whole new world to learn, good i know what has to be done,even not how?
the PID face plate is the biggest challenge, still need a Indicator and DCD faceplate.
the Operation is basically only by that faceplates,
a "operator" page needs a background, could be a real plant / equipment photo, a 3D drawing with vessel and pipes, or a schematic pipe and Instrument diagram. there are to be dynamic elements like ON/OFF valves and motors ( blue stop / green run / red fail ) and level bar graphs for vessel..
but NEVER a click on any of that equipment ( in that display ) should be a OPERATION,
better just a link to open one of that OPERATION faceplates for that clicked point.
30 years ago there was just the beginning of the operator displays... usually just face plate groups of all points in one page.
But you see, the number of different dynamic elements is not that big, even in PCS Configuration systems with blown up SCADA design tools, you just do PID / IND / DCD faceplate, a Valve / Motor / level Dynamical templates and a static background what could be a picture ( for my uPCS in RPI i used a screen shot of a 3D vessel / pump / pipe / instrument while i made it using Google SketchUp.
// EXAMPLE OLD PROJECT //

so, back to the PID faceplate:
a PID need 3 bar graph PV, SP, OUTPUT, 2 slider SP ( in AUTO mode ) and OUTPUT ( in MAN mode ) where its nice to have the option to use the slider or the number input,
and a checklist for mode: MAN, AUTO, ( CAS, RSP, SAVE )
for the point info need:
TAG NAME, TAG DESCription, Engineering Units, and PV and SP are to be scaled between LOW and HIGH range.
optional alarms PV: LL, LO, HI, HH, DEV ( PV-SP) and for OUT: LO, HI might be indicated,
depends on point config options.
the last operation (blue) buttons row is:
-[PID] means open the tuning display for this point
-[CT] means show the current trend ( a short time trend PV, SP, OUT helps with tuning..)
-[HT] means show the historic trend ( possibly only PV over month )
-[SEND] the original execution button to send changes to Arduino.


so besides working on protocol on arduino and RPI python side i want here make a environment
to work/play with modern bar graphs ( start HTML CSS)
but i have some problems to apply CSS? so the result is a HTML5 NoNo.

actually i hate that relative object packing, i want something like a box ( where i can say where it shows up ) and a absolute pixel position of graphical objects inside that box.
so i try SVG like from here just for test inside my face plate play-page

as the principle works i can go to the details. Here info about SVG Animation.
83 S 86 V 71 G 32 space 105 i 115 s 32 space 99 c 111 o 111 o 108 l 33 !
that was my own SVG made WEB FONT build into this PHP Fusion CMS ( with edit BBCode using a PHP insert trick ).
first i play with external SVG file, but now with the SVG code inside HTML so
the usage of Python Flask variables is more easy, here but still only static:

from static to dynamic is so easy when you work with Flask,
first make a little array for 2 points
and HTML shows 2 times the SAME face plate, using the different data.

or make all 6 UNO points / build more visibility switches in SVG



there is no operation concept until now besides:
each faceplate already have a link to a detail page, where you see the ONE faceplate and
default HTML 5 elements buttons, option selector for MODE and sliders for OUTPUT and SETPOINT ( no vertical ! )

ugly but already working ( regarding commands back to PYTHON .. what later has to send it to Arduino)


must test better sliders ( look jqueryui.com/slider/ )
i see in footer.html that we load already
/assets/js/jquery.min.js ( version 1.11.3 )
above slider uses

code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css
/resources/demos/style.css
code.jquery.com/jquery-1.12.4.js
code.jquery.com/ui/1.12.1/jquery-ui.js

when i load it in a index.html file in my PC the style thing not work?? but some blind sliding is ok, a CSS issue. So, the good way is to download that JQuery-UI project after selecting ( like slider ) what you need from here.
then in a PC directory i play long time until i got 2 vertical slider with 2 colors and then copy to this FP_detail.html ( incl CSS and JS ..)

where i use a table to arrange the
barfaceplatebar
mode buttons
send buttonback button



or even operation of SVG objects inside SVG


yes this is more a study how i could do it in web / HTML ++
but i already develop parts of the application.
so for every call of a page i have to setup the data:
until now it is 3 step:
-1- make a array ( of 6 TAGs ) with the static of the point config like names, descriptions, engineering units, all you need at the visualization level and you not have/need on the controller level.
Arduino only know 'PID1'
and
RPI have to show "LIC01-01" " level V01" "pct" low and high range..
-2- i have to init some PV ( SP , Output , Mode ) values to test the templates PID / IND / DCD ( visibility switches in SVG )
-3- i have to use that PV ... values to calc some graphic positioning inside SVG
but also some other things like the RANGED PV / SP i do outside the SVG and hand it by add columns.
now -2- is only for the test here but there should later come real data from the Arduino!
so i need to start GOOD here already with a real data flow handling:
-1- i already have a CMS but for that 6 TAG names it not makes sense to do a SQL thing
so i stick with the python list
file: flask_app.py use import rpi_upcs2.py
( its now external because the "service"-program need it too )
function: def make_DBI_list():
DBI_list=[
{'DBI':1,'AN':'PID1','TAG':'LIC01-01',....},
{ .. },
{ .. }
]
BUT: only for boot and the static TAG info ( and the cross ref to the NAME in Arduino like "PID1" )
more columns to come:
- variables PV SP OUTPUT MODE are readback from ARDUINO
( and have to have a boot init there, as the arduino is supposed to CONTROL even without RPI )
- tuning gain reset rate alarm limits also are readback from ARDUINO
so there is no other way ( as i did it for uPCS already) to have a readback function, a command RPI >> UNO: send me all current settings for ONE/ALL point
( like before i open a faceplate group or tuning window and definitely at program INIT )
and with that it is clear i will need a server program to handle the communication,
( still not know if FLASK can do that TOO?)
but for the web server data flow i use same way as for the firmata test:
INIT a python list, write it to a ram disk file,
at every page ( call / refresh ) check if ram disk file exists
if read or set variables store it in that file too.
so this file is the memory between the HTML page calls.
any server program ( like for continuously reading point data and store to historic trending ) have to use / update that file too,
AND it could be SPAWNed at the moment the file is made.
so this change is easy:
if file exist read , else init array and write to file.
def get_DBI_list():
UNO_ramdiskfile="/run/shm/uno_dbi.dat"
if (os.path.isfile(UNO_ramdiskfile)):
with open(UNO_ramdiskfile,"rb") as f:
DBI_list = pickle.load(f)
else:
DBI_list = make_DBI_list()
with open(UNO_ramdiskfile,"wb") as f:
pickle.dump(DBI_list, f)
# spawn UNO communication process here
return DBI_list


def make_DBI_list():
# PID FP data array def ( TAG STATIC )
DBI_list=[
{'DBI':1,'AN':'PID1','TAG':'LIC01-01','DSC':'level V01','EGU':'pct','PID':'visible','IND':'visible','MOD':'AUTO',
.
.

pls understand, if the arduino is ready connected and the RPI is to be used as "uPCS2" then the server should start at boot ( for datalogging.. even the visualization/operation is not used.
but what i do here is a FLASK test "Maker" BLOG...
so i want start that system ( as a optional example ) only if YOU select that webpage.( for the first time after boot )

info: again that file is owned by root as i start Flask python with sudo


if you got lost in the revision thing, i changed many html files
using a different idea for include combined with a switch i load ( as data ) with the template. that is a big clean up regarding header and footer files.
while some FP_x files still in work and carry full header and footer until JS + JQuiry ... is tested.
that change is very detailed documented in the help.html in the rev from 0.8.9.a to 0.8.9.b
Besides the Group ( HTML style ) of the big faceplates i also try make smaller ones (mini_faceplates)
also in HTML as group with link anchor for detail display, by html include ( what can not be positioned on a other picture...
And as dynamic elements inside a process overview picture. There i use SVG inside SVG ( what makes it possible to position when i add a cx cy column to the TAG_list. Sadly the link anchor does not work inside SVG.
but not look too bad ( using the old picture as background. But all is far away from this



i must now begin with the upcs2_service.py, the stand alone app
for the USB interface and storing data to ram disk.
it shares same rpi_upcs2.py code and definition of the loop point database,
so it does not matter which one starts first after boot, the ram disk file will be created.
if the communication with the Arduino UNO running uPCS2web sketch can be established it can call for data.
currently there is only the protocol test with simulated sinus PV to catch. but that is already half the job, can already do
-1- save good data to ram disk file /run/shm/uno_dbi.dat
-2- bad data to the ram disk log file
-3- data history :
current trend to a ram disk file ( to show for tuning.. in detail window.. )
historic trend by sqlite3 to uSD or USB disk ( incl time stamp )
Now just for ref: my old RPI python and arduino send data projects can download
here, i also load but not install just to have some python serial code to copy from.
i find a arduinostream.py file ( made for windows/python and RPI/python )

prior to the job USB open... tha basic loging:
a ram disk file /run/shm/uPCS2service is created for log.
now how to use? there is a new web page FP_service.html from /menu/ FP service log
what can show that progress / or errors online.

and introducing the uPCS2 Button Bar for easy operation

back to the service python code, i was thinking that's a fast copy and just check on the new protocol syntax...
well i was wrong: python3 has
- for ser read write a byte array thinking and conversion to string requires encode and decode.
- the timer.clock() give me hard time!! not in seconds ( anymore ) it just must be replaced by time.perf_counter()
so end of day i just get the arduino sending and i see the measuring lines ( from above pv simulated protocol test sketch ).
now taking these lines apart and compare with the DBI list and write to ram disk file is heavy coding.
while change value and save is the easy part.
- load DBI list from ramdisk
- find DBI number what fits to measuring line loopname like 'PID1'
- find a attribute like PV ( what actually not must exist / it would be appended ( as column )[ a sql dream ]
- check value if real or string and convert
- change: DBI list[DBI][attribute]=value
- save to ram disk file with: pickle.dump(DBI_list, f)


to check the string to attributes by separating the inner {} string by its ',' if any,
i needed Arduino send me a test line for this like
pi@RPI3:~/projects/flask_python/myblog $ ./start_service
start python arduino service, stop with [ctrl][c]

init_run_UNO.sh
# try open USB port: /dev/ttyACM0
# ser open looks good
{'UNO1':{'D0':1},'CP':1} command to start reporting
UNO1 booted boot msg i want in sevice log
{'UNO1':{},'CP':1} uno acknowledge reporting command
{'PID1':{'PV':52.78,'SP':50.00,'OV':27.22,'MOD':2.00}} 4 attributes list by ','
{'IND1':{'PV':10.78}}
{'PID1':{'PV':53.47,'SP':50.00,'OV':26.53,'MOD':2.00}}
only with a update rate of HTML display 10sec, but still faceplate show this changing / simulated sinus / values!
117 u 80 P 67 C 83 S 50 2 32 space 105 i 115 s 32 space 76 L 73 I 86 V 69 E
what else to do if incoming data?
+ current trend ( to ram disk / default all analog values ( PID 1sec, IND 5sec )
+ + historic trend ( ? 5 / 10 min ? timer to SD or USB drive)
but whatever we later decide whats best trending, i could start full with a numpy array with timestamp
its more easy to the data reduction later, but looks like it would require installation.
anyhow i look up for array fix length used as ring buffer! my gosh
self pointer of automatic change class... or real shuffling of arrays deque or roll ... LOL

want play python3? code
the uPCS background service program upcs2_service.py makes a trending to 2 floatingpoint matrix ( ring buffer )
PID1 timestamp, PV SP OV MD ( stored at PID1 PV update )
INDx timestamp, IND1PV, IND2PV, IND3PV, IND4PV ( stored at IND1 PV update )
( also every time i get data from Arduino i save time to UNO1 .'TS' ( as float seconds )
and at the DBI_list check ( time - UNO1.'TS' > 6sec ) Alarm "TIME OUT"

at same point ( about every 5 sec ) both arrays are exported to ramdisk to be used in a new FP_trend display
means ( ringbuffer pointer logic ) to make temporary JSON record list and that dumped to ram disk file.
in the trend display called by [ CT ] button i now see the trend data ( from a trend array of currently only 20 records )

that i have to bring into a GRAPH!
right guess: i try SVG again, after 1 hour

that is the idea, later 600 values to 600 pixel graph
no operation needed as that is max resolution and max data.

historic trend OPEN

and supply loop data and mv data in tool tip ( mouse over )


after revision that UNO send all point details, incl all tuning parameters,
( service has to ask for it at the very beginning, after UNO boot, before enable reporting)
i show that parameters in NEW detail page:

and CT trend array to 600 samples ( for PID and INDx )

as i have web server and UNO service running i see no load on the RPI3, but i do get error in trend display "pickle load: run out of input " / need to refresh screen.
python has no internal multi user file management?


what i obviously not mentioned: the other communication way:
OPERATION!
i use same way like with older projects, a ramdisk file just for the command line, from the HTML i generate the JSON command line,
write it to a file /run/shm/uPCS2cmd
the uPCS2service reads it, applies a CP counter and sends to serial Arduino.
and there is already a control code in test:
A0 analog in to PID1 PV, -> PID1 code, -> D2 pwm output
A1 .. A4 analog in to IND 1 .. 4


run in AUTO and MAN, change SP all while the PV is "locked" to the 3V3 pin of arduino board.
so difficult to understand reaction, but PID is running, need to check more details, esp. the feature tuning of Anti Reset Windup..
anyhow current project status is tuning only by Arduino IDE and upload.


when web server is started and you select ( after login ) a uPCS page
( it sees the ram drive is empty ) and the uPCS2service is started. after 7 sec wait and 5 sec init data update the data reporting is enabled. then have 2 open terminals with LOG of HTML server and LOG of UNO service. not much load on RPI3.

related to the diagnostic and simulation switches in Arduino D1,D2,D3,Ds
i made a button bar in [LOG] ( service log ) for operation.

as i here switched: DS ON must see the trend:



the used Arduino code is done by Arduino IDE 1.8.1
and i changed the preferences from /home/pi/Arduino/
to .../myblog/tools/sketch_book/
pls find: FLASK_PID sketch in the next ZIP.


p.s. here i just verify again the install procedure on a new system setup on a RPI2 connected with a arduino leonardo,
wget http://kll.engineering-news.org/kllfusion01/downloads/myblog_089e.tar.xz
unzip with:
tar -xvf myblog_089e.tar.xz
ls
myblog myblog_089e.tar.xz
cd myblog
from .../myblog/ do
./install.sh
./start ( or new desktop icon )

install arduino IDE, upload sketch from .../myblog/tools/sketchbook/FLASK_PID

MYBLOG:
browser: RPI_IP:4567 (or localhost:4567 on browser inside RPI )
login admin default
/menu/ uPCS ( and second terminal window open with the arduino communication )


that is not the end:
i see that some diagnostic things are difficult to see in the terminal windows, so i added again
a command to disable (auto) reporting D0 ( what is a command from web page to service, what is send to arduino but also used in logic inside service, so D0 = 0 must disable the automatic send of D0=1...
thinking about Historic Trend:
need a timer:
HTrend_mem ( last storage )
HTrend_delta historic sample time ( 600sec = 10min ?)
and i want do a averaging of the measured values like every incoming value is stored as
PVht = (PVht + PVnew )/2.0 ( a numeric average filter..)
so at HT sampling no add calculation needed.
record:
{'TS':tt.tt,'PID1PV':xx.x,'PID1OV':yy.y,'IND1PV':zz.zz,'IND2PV':zz.zz,'IND3PV':zz.zz,'IND4PV':zz.zz',DCD1PV':zz.zz}
i think it is understandable that the PID output is essential to monitor,
the project, where this setup might be used for, needs to control ( stabilize) a current,
because it seems to be depending on parameters ( we want monitor in the IND points ) like
salt content...
if the control is working ( PID PWM output to PS hardware control voltage ) the current will be constant,
the IND values might change or not, YOU learn nothing!
unless you can correlate the PID output with that INDx parameters...
like: need higher voltage at lower salt content !!!

what to do with that record?
at first i will just save it in clear JSON/text ( or better CSV numbers only )
with a easy file: open append close
-a- to a USB stick ? if at boot / start USB stick and file there is not found?
-b- to RAM DISK
RAMDISKpath = '/run/shm/'
HTfilepath = '/home/pi/media/USBstick/'
HTfile = 'HTdb.csv'
so even your stick has that NAME that file must exist already to be used as storage.

while the code works alread, there is no header line in that file, essential for a good CSV, done.
( there is a obvious advantage if a long JSON line )
so, in /tools/HTdb.csv is a template file, you can copy to stick and all should work this way too.
You see, there is a starting 0.0 value line at service start, so every boot or restart is documented even graphs will look ugly.

for the HMI i see 2 ways: including a historic trend display
starting with a list of TAG data.
while for the Current Trend i know the buffer length and a trend bar graph style was easy, the Historic Trend has unlimited length / and good that a HTML page not run out of paper, i want give the LINE CHART a revival with combining it with the detail quality of SVG.
while on the printed ascii line i have 80 .. 100 positions of a character
for a 100.00 [%] (from 10bit arduino ADC ) data,
in SVG i can work in pixel. first test 600px graph:


( for play i use a HT sample rate of 1min, pls find that parameter at: upcs2_service.py / line 51 / HTrent_delta=300.0 #sec )
change to circle (bullet style) and tool tip incl calculated PV in % and range
and a width of 1000px so its 10bit resolution!


or just download the CSV to the user for local evaluation / storage.
what i actually don't know how to do, as the ram disk is not reachable from HTML, just a link to the file did not work, so need a other HTML page with pure CSV data.
anyhow pls note that the data are all in 0. .. 100. %, for the CSV report the Range conversion is done. use browser tools like ?FILE/SAVE AS/ FP_HTCSVxxx.csv and import to excel calc ..
as Comma Separated Value.






Alarming:
for the safety of the equipment ( and quality of the product ) PCS use alarm packages what include not only alarm generation and reporting
also alarm handling like alarm enable disable ( password protected ) alarm acknowledge with logging (user) and keeping a alarm stack... for handling several alarms on one attribute (PV) and their status.
here i only want use the first two steps.
Arduino checks ( at new PV ) according alarm limits.
on new alarm send single report 'ALM' ( 0.0 1.0 2.0 .. )
the sequence has to with priority, the most urgent alarm must be the last one ( like HIHI )

service writes a entry in syslog and data
and visualization translate to ALARM WORDs ( on point type ) and show in faceplate.



and rework mini faceplate in OVVW



here i write a little bit about DCD point types, (like: Discrete Control Device (DCD) Points in EMERSON Fisher Rosemount DCS )
or whatever you name it. while PID and IND are analog input types a DCD is like a PID for digital I/O.
it can be only one digital input ( to make a alarm ) or a 16bit word in and out from a fieldbus device like a motor/inverter.
the DCD point is just the envelope for the communication CONTROL <--> OPERATION.
inside control ( Arduino ) a DCD is actually a PLC of its own.
or a logic framework we are free to design now.


indication and alarming and operation:
we select a list of digital inputs and outputs, read inputs in a background job ( PLC style much more often as the 1sec / 5sec analog points job control ) and check on change of inputs, only then start the logical point what will report changes of point status.
for operation we get a SETPOINT ( 1.0 .. x.0 ) and translate this to a (sub) set of outputs we have to drive ( high or low )
so instead of making several digital points like one MOTOR and a LevelSwitch LOLO (alarminput) and a startup valve relay output we can do all inside one DCD (reporting) point.
LevelSwitch LOLO (alarminput) ( if Din_17 OFF ALM=33.0 ( "L_LOLO" DCD alarmword ) else 34.0 ( reset alarm )
operate / send SP 12.0 drive Dout_3 HIGH ( relay ON diverter valve active ) / SP 13.0 drive Dout_3 LOW ( relay OFF diverter valve NOT active ) ...
for other details see HELP.html

code 0.9.0.b


test socket IO
now while i with this make a webpage to show and operate uPCS
( compared to the older projects with python desktop programs GUI )
still i use the old trick
- one python background service handles the USB and read ( command ) write ( data ) to RAM DISK FILES.
- while the new web server reads the data and writes the command files there.
i was told SOCKET IO ( using node.js ) could solve that problem.
so i take a side step to here.