My Pi Description

My Experiences With the Raspberry Pi -- Tracking My Learning -- My Pi Projects

Friday, October 18, 2013

Can A Python Script With GUI Run From Root? Not A Trivial Question. Answer: Yes

Important Preface: While I mention graphing results of measurements in the next paragraph, this post is about the Graphical User Interface. Even though graphing and Graphical contain the word graph, this post concerns a problem related to the Graphical User's Interface and not any problem graphing results.
My last blog post is about my python program that measures temperature and then graphs the results. When that script runs, the user is faced with many questions to answer. All that typing gets quite tedious after a while so I thought about including a GUI (Graphical User's Interface) to deal with the questions. I started slow and included a pop-up window for the user to select a file name. I used the Tkinter module, included in python 2.7. Seemed simple enough. Of course, due to the RPi GPIO code, the script has to be run as root (prefacing the command with sudo). It didn't work!
I got an error: “Client is not authorized to connect to Server…..”. What!!! This error really floored me. I posted a question on the Stackoverflow forum and was told that I should use gksudo or its cousin gksu instead of sudo (gksudo is related to gksu as sudo is related to su).
What is gksudo/gksu? The Linux manual page says: "Their primary purpose is to run graphical commands that need root without the need to run an X terminal emulator and using su directly." The first part of that sentence sounded to be just what I needed. So, I played around with a simple script and ran it with gksudo. It worked fine. Then, I tried more complex scripts and I noticed they almost worked. Finally, I tried my large temperature measuring program run with gksudo (no GUI code in this script), and IT DID NOT WORK AT ALL.
Now, what? Every time I ran a script using gksudo (or gksu) I received this error message: "Xlib: extension "RANDR" missing on display "1.0". I had no idea what that meant but decided I had to find out how to get around it. Consequently, I did a search on RANDR. I found nothing to explain what RANDR is but I found quite a few forum posts where people asked about the exact same error message. This message pops up in a diverse universe of Linux applications run on a variety of platforms. There were a lot of answers, too. However, none had a solution I could use. Many of the answers said to ignore the error message. In my case, I knew I could not ignore the error - my script fails.
I next posted the question on the Raspberry Pi forum and the Stackoverflow forum. I explained about getting the no permission error with sudo, and the RANDR error with gksudo and the fact that my script fails. My responses on both forums was no response at all.
Finally, my son helped me out by pointing me to a forum post he found that gave me the answer that worked:
To the bottom of this file:
          pi@raspberrypi: ~/.bashrc
Add (first line optional):
          # allows X11 graphics to be run from root
          xhost +
The first line, of course is just a comment. What is xhost + doing here, and why?
The Linux manual page says that xhost is used to add and delete host or user names to the list allowed to make connections to the X server. By saying xhost +, we give every Tom, Dick, Harry, and Edward Snowden permission to connect to the X server. This includes root.
And, what is X server? From the Linux Information Project, "An X server is a program in the X Window System that runs on local machines (i.e., the computers used directly by users) and handles all access to the graphics cards, display screens and input devices (typically a keyboard and mouse) on those computers." The X window system used by the Pi's Linux distribution is X11.
Since we give everybody permission to make connections to the X server (xhost + does that), are we putting our Raspberry Pi in danger? If you have other users that have access to your Pi, they may be able to pop a window into your display space. But, if you are the only user there should be no danger of applying xhost +

Wednesday, October 2, 2013

Graphing Real Temperature Data Using RRDtool and PyRRD

My previous blog post, "RRDtool for Dummies Like Me" was a tutorial on the use of RRDtool and PyRRD to graph data from a python script. For simplicity, I used made-up data. This post talks about plotting real data taken with the Raspberry Pi.
In June and July of this year, I wrote five blog posts about measuring temperature with the Dallas Semiconductor DS18B20 One-wire temperature sensor. The temperature measurements were reported to the terminal screen and my 16x2 LCD display (seen in photo in blog header) so would not be saved. I did modify the script to send the results to a file but have not reported on that effort. Perhaps that would make a worthwhile post for later.
It just seemed natural to want to plot that data to see the change of temperature with time. That led to my investigation of RRDtool and PyRRD, and to the tutorial in my last post. This post combines temperature measurements with plotting in a python script.
I have two DS18uB20 temperature probes in my system. One looks like a small transistor and sits on the breadboard and the other is at the end of a cable. For the graph below, I put the cable sensor in a glass of hot tap water while the breadboard sensor measured ambient air temperature.
The python code follows.
The script is an evolution of code I reported on previously. All the One-wire temperature code was discussed in my June and July posts. The plotting code grew out of the code in the last post. The code for the LCD display came from my posts of March and April of this year.
My python script may seem pretty large, but I wanted to make it useful, and to incorporate all of the hardware connected to the Pi that makes sense to use. These are some of the features:
  1. Choose to use either sensor, breadboard or cable, or both sensors.
  2. Choose graph characteristics:
    1. If desired, give the breadboard, and/or cable sensor another name.
    2. Give the graph a title - mandatory
    3. If desired, enter a comment that prints on the graph.
    4. Select graph with either black or white background, or choose to make both graphs. White background is best to print. It's easier on printer ink. I think black looks better on the screen, like as seen in the sample graph.
    5. Enter the height from 100 to 400 pixels. If you are plotting from one sensor of a temperature that does not change much it is better to choose a lower value for the height. Otherwise, RRDtool may repeat the values on the Y axis, like: 70, 70, 70, 71, 71, 71, 72, 72, 72, etc.
    6. Choose a file name. Up to four files will be created with that name: an .rrd file for each sensor chosen, and a .png file for each background color chosen.
  3. Choose the maximum number of measurements to make for each sensor. The script will stop once that number of measurements (for each sensor) is reached. In the future, I may modify the script so that once the maximum is reached, new measurements replace the oldest measurements. Remember, this is how a round robin database works.
  4. Choose the time interval between measurements, in minutes. For each sensor: The first measurement will be taken at the first time corresponding to the time interval. For example, if the time is now 37 minutes past the hour, and 15 minutes is selected as the time interval, the first measurement will be at 45 minutes past the hour. If you select the time interval to be one day, the first measurement will be made at midnight. When making the plot, RRDtool will only place a measurement point at a time corresponding to the nearest measurement interval. Again, as an illustration, if we choose a day as the time interval, and we made a measurement at 8PM, the plot will show the measurement at midnight, and --- unless it is the first measurement, the value will be different. That value is not even the linear interpolation of the measured value. See my past post. Strange, but that is the way the tools work.
  5. After entering all of the user information, you have a chance to review and enter the information again, if you are not satisfied.
  6. You can choose not to proceed after entering the user information. This will stop the script.
  7. As well as plotting the temperature data, the average temperature for for each sensor, is calculated and displayed below the plot.
  8. The current measured temperature value, for each sensor, is displayed on the 16 character by 2 line LCD display.
  9. All measurements are sent to the terminal along with the time of the measurement.
  10. There are three ways to stop the script:
    1. When we have reached the maximum number of measurements.
    2. Pressing CTRL-C from the keyboard (Issuing a keyboard interrupt).
    3. Hitting the switch on the breadboard.
There were two things that did not work out as I wished. The first is that RRDtool/PyRRD makes adding some text to the graph somewhat difficult. The title requires you to escape all spaces and probably some punctuation. A space needs to be "\ " in the variable (title_it). It's so easy to forget to add that backslash that I tried to have the script do that for you. It would seem that the following would work:
      title_it = title_it.replace(" ", "\ ")
It doesn't. It replaces a space with "\\ ". This is a title prints on the graph: This\ is\ a\ title, which looks pretty dumb. The following does not work either, giving the same result:
      title_it = title_it.replace(" ", r"\ ")
Since I had no luck adding the backslashes before the spaces, I have the script, in the function check_title, check that the user added the backslashes. Note that the user type "\ " for each space, but the function looks for "\\" before each space (line 103). That makes sense, the first backslash escapes the second backslash.
Here's the second thing that did now work out: I wanted to handle all of that user input with dialog boxes. Using stdio is a bit clunky and if you decide to change some input, you have to enter everything again. Besides, I wanted to learn to incorporate those features. Python has a nice module called Tkinter which brings the graphic users interface to python and other programming languages.
I experimented with a simple program to bring up a dialog box to enter or choose a file name. It worked just fine. I could run it from a Idle Python shell, or from the stdio. No problem. Then I incorporated some GPIO code which meant I had to run the script as root. Now it failed. It threw an exception saying, "Client is not authorized to connect to the Server .....". By client, I assume it means root. Obviously, if the user is me, it works fine, but not if the user is root.