{HowTo} turn on/off your monitor (Time based, PIR/Button, App)



  • Hi all 😉

    Since there were several questions in the Forum for the best way to turn off and on the monitor i wrote this tutorial and try to show the mostly used options.

    The meaning of this tutorial is to get the most used options at the same place 🙂
    So i hope it is ok for the developers of the modules/scripts when i maybe write the installation guide a second time. 😃

    Please keep in mind, that i wrote some parts just out of my head. I tried all options listed here some time ago and all were working. Nevertheless it could be that i forget some points, but if so don’t hesitate to hit my face 😛

    Many thanks to all developers, who wrote these great modules and/or scripts.
    @paviro (MMM-PIR)
    @Jopyth (MMM-Buttons)
    @cowboysdude (pir script)
    @mochman (Whitelist HowTo)

    Oh…and i am open for any suggestion

    So…

    The very important thing is, that your monitor supports HDMI-CEC or ARC. Otherwise u will not be able to turn it on or off via HDMI.
    To reassure you, most monitors do this 😉
    To check if it works just go into terminal via ssh and type:

    sudo tvservice -o to turn off
    sudo tvservice -p to turn on

    edit: for some monitors the following commands work better. Please use them if your monitor needs it:

    vcgencmd display_power 0 to turn off
    vcgencmd display_power 1 to turn on

    We will define in several possibilities:

    Using

    1. Software handling via Cronjob (time based)

    2. PIR-Sensor (HC-SR501)
      1.module version
      2.external version

    3. App

    4. Button
      1.module version
      2.external version

    5. Relays (monitor will be totally shut down!)
      1.button version (toggle function, on/off with every press)
      2.PIR version

    6. Just turn monitor content black (monitor is still on, but u got a black screen)


    1. Using Cronjobs

    So lets start with the most easiest way. There is no optional hardware needed and u will be able to turn on or off the monitor at specific days and daytimes.

    For your understanding how cronjobs works u should note the following:

    * * * * * user executive_command
    ┬ ┬ ┬ ┬ ┬
    │ │ │ │ │
    │ │ │ │ └──── Weekday (0-7, Sunday is 0 or 7)
    │ │ │ └────── Month (1-12)
    │ │ └──────── Day (1-31)
    │ └────────── Hour (0-23)
    └──────────── Minute (0-59)
    

    Next steps we will do as root to be sure it works. Maybe not the best way, but i am just a simple guy, who is still learning the stuff. ^^

    Lets say we want to turn on the monitor every day at 6am and turn off at 8pm:

    sudo nano /etc/crontab (to open the crontab)

    write this into the file:
    0 6 * * * root /usr/bin/tvservice -p >/dev/null 2>&1
    0 20 * * * root /usr/bin/tvservice -o >/dev/null 2>&1

    your crontab file should look like this:

    # /etc/crontab: system-wide crontab
    # Unlike any other crontab you don't have to run the `crontab'
    # command to install the new version when you edit this file
    # and files in /etc/cron.d. These files also have username fields,
    # that none of the other crontabs do.
    
    SHELL=/bin/sh
    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
    
    # m h dom mon dow user  command
    17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
    25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
    47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
    52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
    0 6     * * *   root    /usr/bin/tvservice -o >/dev/null 2>&1
    0 20    * * *   root    /usr/bin/tvservice -p >/dev/null 2>&1
    #
    

    This was simple, right?

    So now we want to turn on the monitor every Mo-Fr from 6-9am and from 4-10pm. On saturday and sunday it will be turned on from 8am-10pm. That would be look like this:

    0 6,16  * * 1,2,3,4,5   root  /usr/bin/tvservice -p >/dev/null 2>&1
    0 9,22  * * 1,2,3,4,5   root  /usr/bin/tvservice -o >/dev/null 2>&1
    0 8     * * 6,7   root  /usr/bin/tvservice -p >/dev/null 2>&1
    0 22    * * 6,7   root  /usr/bin/tvservice -o >/dev/null 2>&1
    

    Alright, thats it. Please keep in mind that this way is the easiest, but probably the most expensive because on at the predefined times even if you don’t look at your mirror.













    2.1 Using PIR-Module

    Probably the most used option is using a PIR and paviro’s MMM-PIR module.

    cd MagicMirror/modules
    git clone https://github.com/paviro/MMM-PIR-Sensor.git
    cd MMM-PIR-Sensor
    npm install
    cd
    sudo usermod -a -G gpio pi (the „pi“ at the end stands for your username)
    sudo chmod u+s /opt/vc/bin/tvservice && sudo chmod u+s /bin/chvt
    nano MagicMirror/config/config.js

    Add the following somewhere between your existing modules:

    {
    	module: 'MMM-PIR-Sensor',
    	config: {
    	powerSavingDelay: 120 // (seconds) how long the monitor will be turned on
    	}
    },
    

    Save the file by typing „ctrl+c“ and „y“

    Connect your PIR as shown here:

    0_1516488144217_PIR.jpg

    We use GPIO-Pin 22 as it is used by default in the MMM-PIR module.
    For all next options in this tutorial we will use pin 22, too.

    Please note: It can be that after you start your MM you have to move once through the PIR to make the module work.













    2.2 Using PIR-Script

    Why using an external script, when there is already a module for that?!
    Well, in my case i use the PIR for several operations. My PIR tuns on the monitor and at the same time a LED stripe is turning on. To do this we need two shell scripts and one python script, which will be activated when booting your Pi.

    cd
    nano monitor_on.sh

    write this in this file:

    sudo tvservice -p
    

    Save the file by typing „ctrl+c“ and „y“

    nano monitor_off.sh

    write this in this file:

    sudo tvservice -o
    

    Save the file by typing „ctrl+c“ and „y“

    chmod +x monitor_on.sh (to make it executable)
    chmod +x monitor_off.sh

    If you want to do other things happen when monitor turns on or off you can simple add your commands or scripts to this file 🙂

    So now you have two options. Write a python script to automatically start the shell scripts by using a GPIO or just put the Shell scripts into a cronjob.

    Here is the first way:

    nano pir.py (creates a script which executes the *.sh files via PIR or Button)

    write this into the file:

    #!/usr/bin/env python
    
    import sys
    import time
    import RPi.GPIO as io
    import subprocess
    
    io.setmode(io.BCM)
    SHUTOFF_DELAY = 120 # in seconds, how long the monitor will be on until next button press or PIR detection
    PIR_PIN = 22       # 15 on the board (this needn't to be a PIR. Can be a button also)
    LED_PIN = 16      # optional, don't use as Relay-PIN. It just shows detection time of the PIR without delay time
    
    def main():
        io.setup(PIR_PIN, io.IN)
        io.setup(LED_PIN, io.OUT)
        turned_off = False
        last_motion_time = time.time()
    
        while True:
            if io.input(PIR_PIN):
                last_motion_time = time.time()
                io.output(LED_PIN, io.LOW)
                print ".",
                sys.stdout.flush()
                if turned_off:
                    turned_off = False
                    turn_on()
            else:
                if not turned_off and time.time() > (last_motion_time + 
                                                     SHUTOFF_DELAY):
                    turned_off = True
                    turn_off()
                if not turned_off and time.time() > (last_motion_time + 1):
                    io.output(LED_PIN, io.HIGH)
            time.sleep(.1)
    
    def turn_on():
    	subprocess.call("sh /home/pi/monitor_on.sh", shell=True)
    
    def turn_off():
    	subprocess.call("sh /home/pi/monitor_off.sh", shell=True)
    
    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            io.cleanup()
    
    

    Save the file by typing „ctrl+c“ and „y“

    chmod +x pir.py

    You can check if your button works by simply typing python pir.py. Every time u move through the PIR or press the button it will show you several …
    End the test with “ctrl+c”

    now we editing the rc.local to start the script after booting the Pi:

    sudo nano /etc/rc.local

    write this in the file (above the “exit 0”):

    python /home/pi/pir.py &

    Save the file by typing „ctrl+c“ and „y“

    after all it should look like this:

    #!/bin/sh -e
    #
    # rc.local
    #
    # This script is executed at the end of each multiuser runlevel.
    # Make sure that the script will "exit 0" on success or any other
    # value on error.
    #
    # In order to enable or disable this script just change the execution
    # bits.
    #
    # By default this script does nothing.
    
    # Print the IP address
    _IP=$(hostname -I) || true
    if [ "$_IP" ]; then
      printf "My IP address is %s\n" "$_IP"
    fi
    
    python /home/pi/pir.py
    
    exit 0
    

    Here comes the second way:

    Next steps are nearly the same as the first option shown in this tutorial.

    Lets say we want to turn on the monitor every day at 6am and turn off at 8pm:

    sudo nano /etc/crontab (to open the crontab)

    write this into the file:
    0 6 * * * root /home/pi/monitor_on.sh >/dev/null 2>&1
    0 20 * * * root /home/pi/monitor_off.sh >/dev/null 2>&1

    Save the file by typing „ctrl+c“ and „y“













    3. Using App

    First i need to say that this isn’t really an App. But you can make it look a like. I just know how to do it with iPhone devices so in this example i will show you how to do it with that.

    We need to install the MMM-Remote-Control module:

    cd MagicMirror/modules
    git clone https://github.com/Jopyth/MMM-Remote-Control.git
    cd MMM-Remote-Control
    npm install
    cd

    In the next step we will add the module to our config.js. To get access to our mirror u should notice the „Whitelist HowTo“.

    nano MagicMirror/config/config.js

    Add the following somewhere between your existing modules:

    {
        module: 'MMM-Remote-Control'
        // uncomment the following line to show the URL of the remote control on the mirror
        // , position: 'bottom_left'
        // you can hide this module afterwards from the remote control itself
    },
    

    Save the file by typing „ctrl+c“ and „y“

    and restart your MagicMirror.

    I suppose that you are knowing the IP-address of your Pi, otherwise u should google how to find out 😉
    Lets say your Pi has this IP: 192.168.178.240

    so know u should be able to get access to the Mirror by typing the following in your Safari-Browser on the iPhone:

    http://192.168.178.240:8080/remote.html

    You should see this:

    0_1516561977045_noname.png

    Tap the „share button“ and tap „Add to home screen“. After that a new „app“ will appear on your home screen.

    If you tap on it u will get a full screen of the Remote-Control module and will be able to turn on and off your monitor 🙂













    4.1 Using Button module

    To use the MMM-Button it is totally necessary to already get the MMM-Remote-Control module running!

    cd MagicMirror/modules
    git clone https://github.com/Jopyth/MMM-Buttons.git
    cd MMM-Buttons
    npm install (this can take a while)
    cd
    nano MagicMirror/config/config.js

    Add the following somewhere between your existing modules:

    {
    	module: 'MMM-Buttons',
    		config: {
     		buttons: [
     		{
      		pin: 22,
     		name: "monitor_control",
    		longPress: {
    		notification: "REMOTE_ACTION",
    		payload: {action: "MONITOROFF"}
    		},
    		shortPress: {
    		notification: "REMOTE_ACTION",
    		payload: {action: "MONITORON"}
    		}
               }
            ]
        }
    },
    

    So if you press your button shortly (0 - 0,5 seconds) the monitor will turn on. A longer press (> 3 seconds) will turn off the monitor.

    Connect the button like shown in the next step.







    4.2 Using Button script

    Why it can be necessary to use an external script i already wrote above.
    And luckily the way to use a button with an external script is the same way as using a PIR.
    So turn back to point 2.2 and do it exactly like described there. Maybe u want to rename the pir.py to button.py, but then you also have to change the cronjob commands or the rc.local entry 😉

    Connect it like this:

    0_1516519962774_Bildschirmfoto 2018-01-21 um 08.31.09.png













    5. Relay
    If you want to safe money or your monitor doesn’t support HDMI-CEC you can simply breaks off the current to your monitor by using a Relay. To keep it simple i will use the srd-05vdc-sl-c relay.

    Keep in mind, that some monitors don’t start automatically by giving them power.

    5.1 - Use Relay with a button:

    Note: The script below toggles the output for the relay. If u want to use the relay with time delay u can use the scripts on point 5.2 and just replace the PIR with a button.

    Note: Some relays are active low. That means, that they are active while the GPIO is set to “0” or “False”. in this case u need to turn the commands for turn_on and turn_off in the python script. So for monitor on u need to write “io.output(RELAY_PIN, False)” and for monitor off “io.output(RELAY_PIN, True)”

    cd
    nano relay.py

    put this code into the file:

    #!/usr/bin/env python
    
    import subprocess
    import time
    import RPi.GPIO as gpio
    import sys
    
    gpio.setwarnings(False)
    gpio.setmode(gpio.BCM)
    BUTTON_PIN = 22
    RELAY_PIN = 27
    
    
    def main():
        gpio.setup(BUTTON_PIN, gpio.IN, pull_up_down=gpio.PUD_DOWN)
        gpio.setup(RELAY_PIN, gpio.OUT)
        gpio.output(RELAY_PIN, False)
        count = 0
    
        while True:
            gpio.wait_for_edge(BUTTON_PIN, gpio.FALLING)
            t = time.time()
            time.sleep(.3)
            gpio.wait_for_edge(BUTTON_PIN, gpio.RISING)
            count += 1
    
            if count > 1:
                count = 0
    
            if count == 0:
                print "Turn screen on"
                gpio.output(RELAY_PIN, True)
            if count == 1:
                print "Turn screen off"
                gpio.output(RELAY_PIN, False)
    
    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            gpio.cleanup()
    

    Save the file by typing „ctrl+c“ and „y“

    make it executable:

    chmod +x relay.py

    You can test by simply typing python relay.py. Every time you push the button your screen will toggle to go on or off.
    So your first push turns off the screen content and your second push turns it on 🙂
    Between every press, u need to wait 5 seconds.
    its that simple…

    Connect the button and the relay like this:

    0_1516558469012_Bildschirmfoto 2018-01-21 um 18.58.16.png







    5.2 - Use Relay with a PIR:

    Note: Some relays are active low. That means, that they are active while the GPIO is set to “0” or “False”. in this case u need to turn the commands for turn_on and turn_off in the python script. So for monitor on u need to write “io.output(RELAY_PIN, False)” and for monitor off “io.output(RELAY_PIN, True)”

    nano relayPIR.py

    put in this:

    #!/usr/bin/env python
    
    import sys
    import time
    import RPi.GPIO as io
    import subprocess
    
    io.setmode(io.BCM)
    SHUTOFF_DELAY = 120 # in seconds, how long the monitor will be on until next button press or PIR detection
    PIR_PIN = 22       # 15 on the board (this needn't to be a PIR. Can be a button also)
    LED_PIN = 17    # 11 on the board (optional): It just shows detection time of PIR without delay time
    RELAY_PIN = 27  # 13 on the board
    
    def main():
        io.setup(PIR_PIN, io.IN)
        io.setup(LED_PIN, io.OUT)
        io.setup(RELAY_PIN, io.OUT)
        turned_off = False
        last_motion_time = time.time()
    
        while True:
            if io.input(PIR_PIN):
                last_motion_time = time.time()
                io.output(LED_PIN, io.LOW)
                print ".",
                sys.stdout.flush()
                if turned_off:
                    turned_off = False
                    turn_on()
            else:
                if not turned_off and time.time() > (last_motion_time + 
                                                     SHUTOFF_DELAY):
                    turned_off = True
                    turn_off()
                if not turned_off and time.time() > (last_motion_time + 1):
                    io.output(LED_PIN, io.HIGH)
            time.sleep(.1)
    
    def turn_on():
            io.output(RELAY_PIN, True)
    
    def turn_off():
            io.output(RELAY_PIN, False)
    
    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            io.cleanup()
    

    save with “ctrl+x” and “y”

    chmod +x relay.py

    You can check if your button works by simply typing python relayPIR.py. Every time u move through the PIR or press the button it will show you several …
    End the test with “ctrl+c”
    The Shutoff delay in the script defines how long the relay will be turned on after last detection through the pir.

    Connect it like this:

    0_1516964458968_Bildschirmfoto 2018-01-26 um 11.59.18.png

    now we editing the rc.local to start the script after booting the Pi:

    sudo nano /etc/rc.local

    write this in the file (above the “exit 0”):

    python /home/pi/relayPIR.py &

    Save the file by typing „ctrl+c“ and „y“

    after all it should look like this:

    #!/bin/sh -e
    #
    # rc.local
    #
    # This script is executed at the end of each multiuser runlevel.
    # Make sure that the script will "exit 0" on success or any other
    # value on error.
    #
    # In order to enable or disable this script just change the execution
    # bits.
    #
    # By default this script does nothing.
    
    # Print the IP address
    _IP=$(hostname -I) || true
    if [ "$_IP" ]; then
      printf "My IP address is %s\n" "$_IP"
    fi
    
    python /home/pi/relayPIR.py
    
    exit 0
    












    6. Just turn black

    Alright, for some reason you might want to be able to just set your monitor content black instead of turning it to standby.
    That can be necessary, if you still want to use your monitor speaker.

    We can do this nearly the same way as shown with the normally used PIR/button script shown above.

    cd
    nano screen_on.sh

    put this into the file:

    export DISPLAY=:0
    xset dpms force on
    

    Save the file by typing „ctrl+c“ and „y“

    nano screen_off.sh

    put this into the file:

    export DISPLAY=:0
    xset dpms force off
    

    Save the file by typing „ctrl+c“ and „y“

    make them executable:

    chmod +x screen_on.sh
    chmod +x screen_off.sh

    Now at this point you got three options.

    1. Use it with cronjob (do it like described at section 1 & 2.2 from this tutorial)
    2. Use a PIR (just replace the *.sh scripts from the section 2.2 and change the shell script names in the commands within the pir.py script)
    3. Use a single push button

    For using the push button you need to connect your button the same way as shown at section 4.2.

    Alright, here comes the script:

    cd
    nano screenbutton.py

    put in the following content:

    #!/usr/bin/env python
    
    import subprocess
    import time
    import RPi.GPIO as gpio
    import sys
    
    gpio.setwarnings(False)
    gpio.setmode(gpio.BCM)
    BUTTON_PIN = 22
    
    #turn screen on at startup
    subprocess.call("sh /home/pi/screen_on.sh", shell=True)
    
    def main():
        gpio.setup(BUTTON_PIN, gpio.IN, pull_up_down=gpio.PUD_DOWN)
        count = 0
    
        while True:
            gpio.wait_for_edge(BUTTON_PIN, gpio.FALLING)
            t = time.time()
            time.sleep(.5)
            gpio.wait_for_edge(BUTTON_PIN, gpio.RISING)
            count += 1
    
            if count > 1:
                count = 0
    
            if count == 0:
                print "Turn screen on"
                subprocess.call("sh /home/pi/screen_on.sh", shell=True)
            if count == 1:
                print "Turn screen off"
                subprocess.call("sh /home/pi/screen_off.sh", shell=True)
    
    if __name__ == '__main__':
        try:
            main()
        except KeyboardInterrupt:
            gpio.cleanup()
    

    Save the file by typing „ctrl+c“ and „y“

    make it executable:

    chmod +x screenbutton.py

    You can test by simply typing python screenbutton.py. Every time you push the button your screen will toggle to go on or off.
    So your first push turns off the screen content and your second push turns it on 🙂
    its that simple…

    now we editing the rc.local to start the script after booting the Pi:

    sudo nano /etc/rc.local

    write this in the file (above the “exit 0”):

    python /home/pi/screenbutton.py &

    Save the file by typing „ctrl+c“ and „y“

    after all it should look like this:

    #!/bin/sh -e
    #
    # rc.local
    #
    # This script is executed at the end of each multiuser runlevel.
    # Make sure that the script will "exit 0" on success or any other
    # value on error.
    #
    # In order to enable or disable this script just change the execution
    # bits.
    #
    # By default this script does nothing.
    
    # Print the IP address
    _IP=$(hostname -I) || true
    if [ "$_IP" ]; then
      printf "My IP address is %s\n" "$_IP"
    fi
    
    python /home/pi/screenbutton.py
    
    exit 0
    








  • Thanks, @cruunnerr. Very comprehensive. Can I suggest you also add how to black out but not disable the monitor? I’ve seen this question a few times. It is often important when users:

    1. want to still use the integrated audio out of a monitor, or
    2. are using a TV style display where it will turn off without signal, and then cannot be turned back on by the Pi.

    I’ve seen solutions using xset dpms force off and another using chvt to display a blank virtual terminal, but there may be other (even better) solutions.



  • is there a way to use a PIR sensor and the PIR module to make the PI load a black screen saver so that it looks like the screen went off but really didnt and then when the PIR sensor picks up motion the screen saver is “turned off” like it would normally do.?



  • @nikobelohlav

    yes it is.

    Just use the external script from this tutorial. Change the content of the monitor_off.sh and monitor_on.sh to the following:

    monitor_off:

    export DISPLAY=:0
    xset dpms force off
    

    monitor_on:

    export DISPLAY=:0
    xset dpms force on
    

    I will add this options to the tutorial later. 😉


  • Module Developer

    @cruunnerr

    Those commands look familiar. 🙂



  • Nice tutorial!
    Time to connect the Pir to the Pi.
    Thanks!
    Peter



  • @nikobelohlav @ninjabreadman

    Alright, i add this option to the tutorial. Hope you enjoy 🙂

    If there are any suggestions on the scripts i am using please tell me. I am not a programmer so it could be, that the scripts aren’t as “clean” as they could be.



    1. disable the HDMI port with
    vcgencmd display_power 0
    

    and enable with

    vcgencmd display_power 1
    

    Most monitors then go into standby. Some also show ‘NO Signal’.



  • @OdomLinx copy paste error?



  • @E3V3A Yes copy paste error, I adjusted it