Forum Replies Created
-
AuthorPosts
-
andrewParticipantAnd now I know what a triac is. It’s been a while since I took an EE class. Thanks for the info, Ray.
andrewParticipantOh indeed, there’s no question that the OS controller is a good deal. It has more features (single power source, shift registers for unlimited extendability), and requires relatively little in terms of install and setup. My question is mostly academic (I have no intention of changing things around at this point anyway). I do think that the relay works with 24VAC, the output is rated to AC250V and since all it’s doing is closing the circuit, smaller voltages shouldn’t be a problem (correct me if I’m wrong here).
One problem is that it seems to require wiring up some resisters and transistors to get it to interface with the RPi. What are you using to control your garage door?
July 25, 2013 at 1:25 pm in reply to: sprinklers_pi – An alternative sprinkler control program #24928
andrewParticipantThanks for sharing! The best part about about Raspberry Pi’s and the OpenSprinkler is that it almost exclusively attracts DIYers, so we’ll have a lot of diverse solutions available. How does your system utilize the wunderground data (e.g., what is it pulling down and in what way does it alter the watering schedule)?
andrewParticipantWith respect to some zones needing more water than others, you can get around that by adding an additional program that activates just the zones that need additional watering. It’s clunky, but it should serve your purpose.
andrewParticipantIf you’re not worried about network issues preventing the slave from receiving commands from the master, you ought to be able to set something up with a relatively small bit of hacking. Let’s call the back yard your master and the front yard the slave. Your master will consist of one RPi, one controller board, and one extension board (which is a shame since you have ports to spare on the front yard). The slave will consist of one RPi and one controller board.
The quickest thing to do would be to configure the interval program on the master RPi to have an additional extension board (two in total), but hack the code so that the data that would be sent to the controller board and its extension boards would be forwarded to the slave instead. Fortunately, this appears to be fairly easy. In the OSPi.py file, find the definition for the set_output() function (line 282 of the current version). It looks like this:
##### GPIO #####
def set_output():
disableShiftRegisterOutput()
setShiftRegister(gv.srvals)
enableShiftRegisterOutput()Luckily, this is the only place where data is sent out to the controller board and its extension boards, so you’ll really only have to modify this area to suit your needs. We’ve configured the master to have an extra extension board, so the first thing we need to do is make sure that the data for that extra board is not actually passed to the controller:
##### GPIO #####
def set_output():
local_srvals = gv.srvals[:16] # get the first 16 stations values
remote_srvals = gv.srvals[16:] # get the last 8 station values
disableShiftRegisterOutput()
num_stations = 16 # the following function uses num_stations, so we temporarily change the value
setShiftRegister(local_srvals) # only send the local values to the master's controller
num_stations = gv.sd # put it back to what it was.
enableShiftRegisterOutput()
Next, you’ll need to add some code to the end of that function that connects to the slave and sends the instructions for the remaining 8 values. I’ll leave that up to you, but you could implement some simple socket connections or use a web server, or whatever. On the slave side, whenever it receives data from the master, it should set its own shift registers accordingly. That’s all the slave has to do. For that, you may simply want to copy the original set_output() function (and dependent functions and variables) and simply call them. I can give you tips on the parts I’ve left out; let me know if you need further help or anything’s unclear. Also, I took some guesses wrt the bit ordering of the srvals array. it may be that the elements you want to forward to the slave are the first 8 elements instead of the last. You’ll just need to play with it.
andrewParticipant@snewman wrote:
Looks like a good solution is to write some kind of long-running scheduler/controller that is the only process allowed to manipulate the shift registers. It can also act as a state manager to keep track of the status of stations. I really don’t want to require people to set up task queues or other network processes, so I’ll probably do it as a simple HTTP-based system that uses threads.
Precisely. You might even want to go a step further and decouple the scheduler from the controller. You’d have one process (the controller, or perhaps more aptly named, the driver) which is the only process that actually interfaces with the shift registers (it would be a single, running process). It should support low-level commands like set_state and get_state which sets/gets the entire state of the shift registers (again, getting the state would have to be implemented by simply recalling the last state that was sent). It might also support some slightly higher-level commands like turning on/off specific stations. Then the scheduler (or better yet, the controller, if you’re calling the other thing the driver) would operate at the level of individual scheduled programs, and it would handle when a program activates specific stations during the execution of a program, when programs are executed, and (most relevant to this thread) what happens when multiple programs are trying to run at the same time (e.g., whether programs are smartly combined, or one overwrites the other, or one is delayed until the other is finished, etc.) This process would also be a single, long-running thread (and technically could be in the same process as the driver; the decoupling is more for organization). You may want to look at some existing scheduling libraries to help with the timing stuff (e.g., http://pythonhosted.org/APScheduler/).
I’m thrilled that you’re working on a separate implementation. I’ve been happy with the interval program in conjunction with the mobile web app, but there’s never anything wrong with healthy competition, especially in the open source community.
andrewParticipant@snewman – The interval program was initially written by Ray, and ported to python for use with a Raspberry Pi by Dan Kimberling.
@Virtus – This question is probably a bit out of scope for this thread, and is best answered by Ray or Dan. If your question is aimed at understanding at a higher level how shift registers work and are used in the interval program, then @Virtus’s response is probably good enough. When any program (including the interval program) desires to change the state of a station, it must specify the entire state for all stations, and will overwrite the existing state completely. In the interface between the RPi and the controller board, there is no notion of “just change the state of station X”. You are always indicating the entire state of all stations and the existing state is always overwritten in its entirety. If, on the other hand, you really want to know precisely what happens in the circumstances you described, the answer may be a bit more complicated. Dan is probably best suited to answer, but from what I can see in the code (and I’ve only taken a cursory glance), you may actually get some very strange results. It appears that if you set manual mode while a program is already running, the manual mode thread will actually be competing with the main loop that is executing the normal program, and it looks like they’ll just go on interfering with each other until either the program ends, or the manual mode is turned off. Each of the competing threads will, during the course of their respective executions, be setting various states for all of the stations Unless I’m missing something (and in fact I probably am), this would be a bug, but not a particularly important one.
andrewParticipantI just posted a feature request that relates specifically to the mobile web app. I could have put it here, but I elected to put it in its own thread because this one is already so long 😀 . Link: http://rayshobby.net/phpBB3/viewtopic.php?f=8&t=230
andrewParticipant@doczaius: I don’t believe that it’s polling anything, and this is the point I was making above. The interval program keeps a variable in memory that represents the current state of the stations. When a station is “turned on” the bit for the station in that variable is set to a 1 (or a 0, not sure which) and then the program calls the set_output function, which then takes the values for all of the stations and sends it out through the GPIO to the shift registers on the controller board. There is no polling of or feedback from the controller board that I’m aware of. The program just assumes that whatever *it* last sent out to the shift registers is what the current status of the controller is. If you’re running the interval program, and then in a separate process send some new values to the shift registers, thereby changing the state of the controller, the interval program will be completely unaware of the change, and still think that the controller’s state is whatever it had previously set it to.
That being said, if some is running the interval program exclusively, they can indeed use http://xxx.xxx.xxx.xxx/snX to obtain the state of the stations (as far as the interval program is aware). I believe, however, that snewman was intending on writing/running his own program and would not, therefore, be making direct use of the interval program.
andrewParticipantBy the way. You mentioned that you are struggling to understand shift registers. This article offers a good explanation: http://bildr.org/2011/02/74hc595/. This will also explain why the the complete state of the controller has to been reset each time a station is opened or closed. The shift register is cleared out and 8 new bits are sent to the register (or more if you are using an expander board; the linked article also explains how shift registers are daisy chained, which is exactly how the expansion boards work — I think).
andrewParticipantI’ll chime in with some blind speculation. Ray (or possibly someone else) will need to provide a more authoritative answer.
If I had to guess, I would think that the communication between the RPi and the OS controller board is one-directional. In other words, the RPi sends commands to the board, but does not receive anything back in the way of status updates. All of the demo programs that I’ve looked at simply remember the last state that it sent to controller. Therefore, if you wanted to obtain the state of your controller (i.e., which stations are open/closed) you would need to query the program that was responsible for issuing the commands to the controller (and if it’s your own program that’s sending the commands, you’ll need to remember the current state in memory).
More generally, I think that what you may be misunderstanding is that every time you muck about with the shift registers, sending commands to controller board, you are effectively setting the *entire* state of the controller, not just changing the state of one or two specific stations. Via the shift registers, you’re basically sending a sequence of 1s and 0s to the controller with each bit representing the desired state of one of the specific stations. If, then, you send the binary 0010100 to the controller, you’re telling it to open stations 3 and 5 and keep all of the others closed. (Let me reiterate, this is speculation. I may have 1s and 0s reversed, and there may be some other details I’m missing. Don’t take this as gospel).
If you want to do some funky stuff with your own program where you are allowing for overlapping jobs, you’ll need to work out the logic on your own and send the complete state to the controller each time you want it to change. For example, let’s say you have the following desired schedule:
- At time t0, start station S1.
At time t1, start station S5.
At time t2, stop station S1.
at time t3, stop station S5.In the above, you have two jobs. One for station S1 which starts at t0 and stops at t2 and another for station S5 which starts at t1 and stops at t3. The commands you’ll need to send out via the shift registers are as follows:
- At t0: 1000000
At t1: 1000100
At t2: 0000100
At t3: 0000000At time t2, for example, even though we really only wanted to turn off station 1, we still had to send details to the controller that station t3 should still be active.
I could give you some additional guidance as to how this might be achieved in your own custom program, but my post is already rather wordy. Let me know if you’re curious and I’ll write it up.
Edit: you may want to consider, by the way, that allowing for overlapping jobs could have undesirable real-world effects. Many users, I suspect will not want multiple stations to be open at the same time because there may not be adequate water pressure to handle more than one station at a time.
andrewParticipantI ran into a similar problem. In the end, the issue was that I had to make sure that I was setting the host for the mobile app to be the exact same ip address as what is used in the interval program. For example, if you run the interval program by calling
python ospi.py 192.168.1.50:8080
then you want to point your mobile app to the same IP and port (192.168.1.50:8080).
If, however, you use the loopback (127.0.0.1), as in
python ospi.py 127.0.0.1:8080
then you’ll need to use the loopback in your mobile app configuration.
I think this all has to do with some pickiness on the part of the interval program as to whether it’s opening up local or network sockets for accepting incoming connections.
Personally, I have my configuration set to use the loopback IP address (127.0.0.1), but if you want to also connect directly to the interval program UI (the one that isn’t quite as sharp looking) then you have to use the outward facing IP address of the RPi.
Edit: If you don’t know what the IP address is that the interval program is set to use, you can check the running processes by SSHing into the RPi and executing
ps -ax
look for the entry that looks like:
4254 ? Sl 0:29 /usr/bin/python /home/pi/OSPi/ospi.py 127.0.0.1:8000
The IP address that I’m using is at the end there (127.0.0.1:8000)
andrewParticipantIf anyone prefers to use init.d scripts over rc.local, you can put the following into /etc/init.d/ospi.py
You’ll need to have start-stop-daemon installed (which, at least, comes installed on RPi and likely other systems as well).
Be sure to change the variable $DAEMON_ARGS to your desired settings, and change $DIR to the location of ospi.py
#! /bin/sh
### BEGIN INIT INFO
# Provides: OSPi
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: OSPi Interval
# Description: Runs the OSPi Interval program as a service
### END INIT INFO
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="OSPi Interval Daemon"
NAME=ospi.py
DIR=/home/pi/OSPi
DAEMON="$DIR/$NAME"
DAEMON_ARGS="127.0.0.1:8000"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec "$DAEMON" --test > /dev/null
|| return 1
start-stop-daemon --make-pidfile --background --start --quiet --pidfile $PIDFILE -d $DIR --exec "$DAEMON" --
$DAEMON_ARGS
|| return 2
# Add code here, if necessary, that waits for the process to be ready
# to handle requests from services started subsequently which depend
# on this one. As a last resort, sleep for some time.
sleep 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec "$DAEMON"
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
#echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
andrewParticipantWell, I got it to work correctly, but I had to completely reinstall the interval program. Perhaps it was using older (and incompatible) configuration files?
andrewParticipantYou ran a test with the same parameters that I have in the screenshots?
andrewParticipantOh right, that was something else I wanted to bring up. S06 and S08 do not show up because they are not assigned as being part of the program, so they are skipped and don’t appear in the preview. What’s a little strange, however, is that S07 (which is assigned to the program) is labeled as S6 (instead of S7). If I view the preview through a web browser with plenty of screen space, the labels show up as expected (S01, S02, S03, S04, S05, and S07). On an iphone, however, it appears that you’re assigning your own numbering scheme to the stations but it only assigns numbers to the stations that are displayed, when it should probably assign numbers to the hidden stations (even if they remain hidden).
As to my previous issue, I’m currently thinking that it’s a problem with the interval program itself. I’ve checked the OS web interface and that preview shows the same oddity. I’ll post the question to its own thread.
andrewParticipantI’m seeing some odd behavior with the preview window. It may actually be a problem with the underlying OS interval program, but I thought I’d post it to this thread first. It may just end up being my own misunderstanding as to how the program settings are interpreted.
In the following screenshots, I have my program configuration.
[attachment=0:3fivn8qt]IMG_1270.PNG[/attachment:3fivn8qt] [attachment=2:3fivn8qt]IMG_1271.PNG[/attachment:3fivn8qt]Basically, I have a program that should run once through stations 1,2,3,4,5, and 7, running each for 10 minutes, all starting at 4:00 am. This would suggest that the entire program would run in about an hour (there is no station delay set). However, in the preview window (screenshot below), it shows the stations as running for about 25 minutes each, ending the complete cycle sometime after 6:00. Any ideas as to what’s causing this discrepancy?
[attachment=1:3fivn8qt]IMG_1269.PNG[/attachment:3fivn8qt]
andrewParticipantI came across that one, but the problem was that the rainfall value was optional, and it wasn’t given in any of the sample queries that I ran. I don’t think we can depend on that one for rainfall quantities.
andrewParticipantDo you mind if I post trivial issues? The software is becoming so mature that those are all I may find in the future. The rain delay button on the main screen is a bit confusing because there are a number of ways that the rain delay can be turned on in the app (manual, rain sensor, online weather), but that button only really refers to manually setting the delay. Perhaps it would make more sense if the label was “Set Rain Delay” instead of just “Rain Delay”.
andrewParticipantThanks, I had also stumbled onto this one. It’s unfortunate that so many weather services require the users to get an API key. Perhaps we could poll the community and see whether they’d be opposed to having to do that.
andrewParticipantAh. I misunderstood your previous post and didn’t realize there was an update. I’ll check it out when I get home but it sounds like you caught it.
andrewParticipantOk, try it with a comma in the location (e.g., Orlando, Fl). For me, that doesn’t work.
andrewParticipantIf I type my location in as “CITY, STATE”, I do not get the little weather status at the top of the screen. If I change it to a zip code, however, it works. If I had to guess without looking at the code, I’d say you weren’t properly encoding your strings for URLs when you query for the WOEID (for shame) :).
Edit: You probably already know this, but just in case I’m not clear. When I say properly encoding URLs, I mean coverting things like spaces to “+” and commas to “%2C”. There are php functions you can use for this.
andrewParticipantWell, I can’t find any historical data sources (providing, e.g., yesterday’s weather) that do not require an API key. Furthermore, the ones that do have API keys are too restricted that we couldn’t use one API key for all of the users to share. I suppose we may just have to stick with what we’ve got so far and perhaps we can revisit if we can identify an adequate data source.
andrewParticipantWeather underground provides daily summaries which include total rainfall for the day. The problem is that users would have to obtain their own API keys and enter them (because the free keys are too limited that we all couldn’t share one).
-
AuthorPosts