0

Sorry, but I've looked at several threads and no one talks about my idea.

I'm currently working with a switch, that will manage the Christmas-tree lights, to turn it on at 18:00 and off at 01:00 (e.g.)

I don't know which option is the best.

I can set a script that switches on at 18:00, wait 5 hours, and then switches it off

I would like to look for its state and change it, but for some reason, I've changed the switch once and no more changes are possible.

This is my current code, very simple.

#!/usr/bin/python3
import RPi.GPIO as GPIO
from time import sleep

GPIO.setmode(GPIO.BCM)
#GPIO.setwarnings(False)

GPIO_ENCHUFE = 27

try:
    GPIO.setup(GPIO_ENCHUFE,GPIO.OUT)      # Here it breaks
    current_state = GPIO.gpio_function(GPIO_ENCHUFE)
    # Cambio de estado
    opposite_state = (current_state+1)%2
    GPIO.output(GPIO_ENCHUFE,opposite_state)
    #sleep(5)
except Exception as e:
    # Cambiar a version email
    print("Algo ha ocurrido\n"+str(e))
    GPIO.cleanup()

Does anyone know any option to keep the switch status after the program ends?

1
  • Personally, I would have the Python program run constantly. Turn your switch/relay on or off according to time within a while loop. – CoderMike Dec 26 '20 at 16:41
2

I like simple. This is how I'd do it:

crontab -e

In your editor, add the following lines to your crontab:

@reboot /bin/sleep 30; /usr/bin/gpio -g mode 17 out  
0 18 * * * /usr/bin/gpio -g write 17 1 
0 1 * * * /usr/bin/gpio -g write 17 0

Save your crontab, and exit the editor. At 6:00 PM (your RPi time), GPIO 17 (pin 11) will go "HIGH"; i.e. the output will be at 3.3V. At 1:00 AM, GPIO 17 will go "LOW". This will repeat every day until you disable it by editing your crontab. You can comment the lines, and save them 'til next year :)


NOTES:

  1. You'll need the wiringpi package installed: sudo apt-get install wiringpi
  2. If your RPi is an RPi 4, you'll need to follow these instructions also
  3. There may be comments to the effect that wiringpi is deprecated. I think that's premature, but this will cover you through this holiday season at least :)
2

You can use simple timers to have full control about the time and switches. Just create a service that will switch the lights and create two timer, one to switch on and one to switch off the lights. First create the service:

rpi ~$ sudo systemctl edit --force --full switch-lights@.service

In the empty editor insert these statements, save them and quit the editor:

[Unit]
Description=Switch lights
After=basic.target

[Service]
Type=oneshot
ExecStart=/usr/bin/gpio -g write 17 %i

Then create two timer:

rpi ~$ sudo systemctl edit --force --full switch-lights-on.timer

[Unit]
Description=Switch lights on

[Timer]
OnCalendar=*-*-* 18:00:00
Persistent=true
Unit=switch-lights@1.service

[Install]
WantedBy=timers.target

and

rpi ~$ sudo systemctl edit --force --full switch-lights-off.timer

[Unit]
Description=Switch lights off

[Timer]
OnCalendar=*-*-* 1:00:00
Persistent=true
Unit=switch-lights@0.service

[Install]
WantedBy=timers.target

Enable the timer:

rpi ~$ sudo systemctl enable switch-lights-on.timer switch-lights-off.timer

Now you can manage time and lights:

rpi ~$ sudo systemctl start switch-lights-on.timer switch-lights-off.timer
rpi ~$ sudo systemctl stop switch-lights-on.timer switch-lights-off.timer
rpi ~$ systemctl status switch-lights-on.timer switch-lights-off.timer

# switch lights manuell on and off:
rpi ~$ sudo systemctl start switch-lights@1.service
rpi ~$ sudo systemctl start switch-lights@0.service
1

The fundamental issue with your code in that the function gpio_function does not return the state of the pin but the actual type of pin (input, output, serial port etc). This is documented here

There are a couple of ways you can handle this issue but first thing to note is that the function GPIO.cleanup() will reset your pin to input with no pull up/down. You need to exclude the pin you are using with GPIO.cleanup(GPIO_ENCHUFE). This is documented here

As for keeping the state of the pin then there are a few ways of doing this (and I'm sure others will have their own ways):

First up is to create a program that handles both on and off status with a delay between them:

set port to output
set switch on
delay till off time
set switch off
tidy up
end program

You can then call this program from CRON at the correct on time

A second way is to save the status to a file and use that to action the switch:

Create a file with a zero in it (use nano or similar)

Read the data from the file
If zero turn off the switch and write zero to the file
If one turn on the switch and write one to the file

You then call this at the required time to change the state of the switch.

A third way would be to pass the status you want the switch as a parameter to the Python program and use the sys module to access it:

Check only one argument passed using len(sys.argv)
Check if the argument is on or off using sys.argv[0] for the parameter
Turn the switch on or off as needed

Note the Python module getopt helps with parameters but is not needed for a simple check like this.

You would then call this program with the correct parameter to change as needed.

The last option I will list is to use the same program and just toggle the current pin state using the input function:

GPIO.output(GPIO_ENCHUFE, not GPIO.input(GPIO_ENCHUFE))

Every time the program is called, the current state is found by the GPIO.input, inverted / flipped by the not and set as the new output value.

Please remember that you must not clear down the pin use at the end with the general GPIO.cleanup() command but use the GPIO.cleanup(GPIO_ENCHUFE)

0

Use pigpio.

#!/usr/bin/python3
import pigpio

GPIO_ENCHUFE = 27

pi = pigpio.pi()

level = pi.read(GPIO_ENCHUFE)

if level == 0:
   pi.write(GPIO_ENCHUFE, 1)
else:
   pi.write(GPIO_ENCHUFE, 0)

pi.stop()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.