Bugsounet Coding

    • Register
    • Login
    • Search
    This Forum is now reserved to registred users!

    Solved mode 8, turning off using DDC commands without changing dtoverlay

    EXT-Screen
    2
    3
    51
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • P
      pink-o last edited by

      Hi,
      thanks for this project, really cool.
      I would like to provide my little contribution.
      I figured out a way to switch off the screen using i2c without modifying the dtoverlay parameter.
      I am using ddcutil tool, more info here
      The commands to use :

      ddcutil setvcp d6 1 // ON
      ddcutil setvcp d6 4 // POWER SAVE
      ddcutil setvcp d6 5 // POWER OFF
      

      install ddcutil with:

      sudo apt install ddcutil
      

      Activate the i2c interface in your Raspberry Pi.

      The complete code of modded screenLib.js:

      /** Screen management **/
      /** bugsounet **/
      
      const exec = require('child_process').exec
      const process = require('process')
      const moment = require('moment')
      const path = require('path')
      
      var _log = function() {
          var context = "[SCREEN]"
          return Function.prototype.bind.call(console.log, console, context)
      }()
      
      var log = function() {
        //do nothing
      }
      
      class SCREEN {
        constructor(config, callback, debug, detectorControl, governorControl) {
          this.config = config
          this.sendSocketNotification = callback
          this.detector = detectorControl
          this.governor = governorControl
          if (debug == true) log = _log
          this.PathScript = path.dirname(require.resolve('../package.json'))+"/lib"
          this.interval = null
          this.default = {
            animateBody: false,
            animateTime: 3000,
            delay: 5 * 60 * 1000,
            turnOffDisplay: true,
            ecoMode: true,
            displayCounter: true,
            displayBar: false,
            detectorSleeping: false,
            governorSleeping: false,
            mode: 1,
            delayed: 0,
            gpio: 20,
            clearGpioValue: true
          }
          this.config = Object.assign(this.default, this.config)
          this.screen = {
            mode: this.config.mode,
            running: false,
            locked: false,
            power: false,
            delayed: this.config.delayed,
            isDelayed: false,
            awaitBeforeTurnOff: this.config.animateBody,
            awaitBeforeTurnOffTimer: null,
            awaitBeforeTurnOffTime: this.config.animateTime
          }
          if (this.config.turnOffDisplay) {
            switch (this.config.mode) {
              case 0:
                console.log("[SCREEN] Mode 0: Disabled")
                break
              case 1:
                console.log("[SCREEN] Mode 1: vcgencmd")
                break
              case 2:
                console.log("[SCREEN] Mode 2: dpms rpi")
                break
              case 3:
                console.log("[SCREEN] Mode 3: tvservice")
                break
              case 4:
                console.log("[SCREEN] Mode 4: HDMI CEC")
                break
              case 5:
                console.log("[SCREEN] Mode 5: dpms linux")
                break
              case 6:
                console.log("[SCREEN] Mode 6: Python script (Relay on/off)")
                break
              case 7:
                console.log("[SCREEN] Mode 7: Python script reverse (Relay on/off)")
                break
              case 8:
                console.log("[SCREEN] Mode 8: ddcutil")
                break
              default:
                this.logError("Unknow Mode Set to 0 (Disabled)")
                this.sendSocketNotification("ERROR", "[SCREEN] Unknow Mode (" + this.config.mode + ") Set to 0 (Disabled)")
                this.config.mode = 0
                break
            }
          }
        }
      
        activate () {
          if (!this.config.turnOffDisplay && !this.config.ecoMode) return log("Disabled.")
          process.on('exit', (code) => {
            if (this.config.turnOffDisplay && this.config.mode) this.setPowerDisplay(true)
            if (this.config.governorSleeping) this.governor("GOVERNOR_WORKING")
            console.log('[SCREEN] ByeBye !')
            console.log('[SCREEN] @bugsounet')
          })
          this.start()
        }
      
        start (restart) {
          if (this.screen.locked || this.screen.running || (!this.config.turnOffDisplay && !this.config.ecoMode)) return
          if (!restart) log("Start.")
          else log("Restart.")
          clearTimeout(this.screen.awaitBeforeTurnOffTimer)
          this.screen.awaitBeforeTurnOffTimer= null
          this.sendSocketNotification("SCREEN_PRESENCE", true)
          if (!this.screen.power) {
            if (this.config.turnOffDisplay && this.config.mode) this.wantedPowerDisplay(true)
            if (this.config.ecoMode) {
              this.sendSocketNotification("SCREEN_SHOWING")
              this.screen.power = true
            }
            if (this.config.governorSleeping) this.governor("GOVERNOR_WORKING")
          }
          clearInterval(this.interval)
          this.interval = null
          this.counter = this.config.delay
          this.interval = setInterval( ()=> {
            this.screen.running = true
      
            if (this.config.displayCounter) {
              this.sendSocketNotification("SCREEN_TIMER", moment(new Date(this.counter)).format("mm:ss"))
              if (this.config.dev) log("Counter:", moment(new Date(this.counter)).format("mm:ss"))
            }
            if (this.config.displayBar) {
              this.sendSocketNotification("SCREEN_BAR", this.config.delay - this.counter )
            }
            if (this.counter <= 0) {
              clearInterval(this.interval)
              this.screen.running = false
              if (this.screen.power) {
                if (this.config.ecoMode) {
                  this.sendSocketNotification("SCREEN_HIDING")
                  this.screen.power = false
                }
                if (this.config.turnOffDisplay && this.config.mode) this.wantedPowerDisplay(false)
              }
              this.interval = null
              if (this.config.detectorSleeping) this.detector("DETECTOR_STOP")
              if (this.config.governorSleeping) this.governor("GOVERNOR_SLEEPING")
              this.sendSocketNotification("SCREEN_PRESENCE", false)
              log("Stops by counter.")
            }
            this.counter -= 1000
          }, 1000)
        }
      
        stop () {
          if (this.screen.locked) return
      
          if (!this.screen.power) {
            if (this.config.governorSleeping) this.governor("GOVERNOR_WORKING")
            if (this.config.turnOffDisplay && this.config.mode) this.wantedPowerDisplay(true)
            if (this.config.ecoMode) {
              this.sendSocketNotification("SCREEN_SHOWING")
              this.screen.power = true
            }
          }
          this.sendSocketNotification("SCREEN_PRESENCE", true)
          if (!this.screen.running) return
          clearInterval(this.interval)
          this.interval = null
          this.screen.running = false
          log("Stops.")
        }
      
        reset() {
          if (this.screen.locked) return
          clearInterval(this.interval)
          this.interval = null
          this.screen.running = false
          this.screen.isDelayed = false
          this.start(true)
        }
      
        wakeup() {
          if (this.screen.locked || this.screen.isDelayed) return
          if (this.screen.delayed && !this.screen.power) {
            this.screen.isDelayed = true
            log("Delayed wakeup in", this.screen.delayed, "ms")
            setTimeout(() => {
              log("Delayed wakeup")
              if (this.config.detectorSleeping) this.detector("DETECTOR_START")
              this.reset()
            }, this.screen.delayed)
          } else {
            if (!this.screen.power && this.config.detectorSleeping) this.detector("DETECTOR_START")
            this.reset()
          }
        }
      
        lock() {
          if (this.screen.locked) return
          this.screen.locked = true
          clearInterval(this.interval)
          this.interval = null
          this.screen.running = false
          log("Locked !")
        }
      
        unlock() {
          log("Unlocked !")
          this.screen.locked = false
          this.start()
        }
      
        forceEnd () {
          this.counter = 0
        }
      
        wantedPowerDisplay (wanted) {
          var actual = false
          switch (this.config.mode) {
            case 0:
            /** disabled **/
              log("Disabled mode")
              break
            case 1:
            /** vcgencmd **/
              exec("/usr/bin/vcgencmd display_power", (err, stdout, stderr)=> {
                if (err) {
                  this.logError(err)
                  this.sendSocketNotification("ERROR", "[SCREEN] vcgencmd command error (mode: " + this.config.mode + ")")
                }
                else {
                  var displaySh = stdout.trim()
                  actual = Boolean(Number(displaySh.substr(displaySh.length -1)))
                  this.resultDisplay(actual,wanted)
                }
              })
              break
            case 2:
            /** dpms rpi**/
              var actual = false
              exec("DISPLAY=:0 xset q | grep Monitor", (err, stdout, stderr)=> {
                if (err) {
                  this.logError(err)
                  this.sendSocketNotification("ERROR", "[SCREEN] dpms command error (mode: " + this.config.mode + ")")
                }
                else {
                  let responseSh = stdout.trim()
                  var displaySh = responseSh.split(" ")[2]
                  if (displaySh == "On") actual = true
                  this.resultDisplay(actual,wanted)
                }
              })
              break
            case 3:
            /** tvservice **/
              exec("tvservice -s | grep Hz", (err, stdout, stderr)=> {
                if (err) {
                  this.logError(err)
                  this.sendSocketNotification("ERROR", "[SCREEN] tvservice command error (mode: " + this.config.mode + ")")
                }
                else {
                  let responseSh = stdout.trim()
                  if (responseSh) actual = true
                  this.resultDisplay(actual,wanted)
                }
              })
              break
            case 4:
            /** CEC **/
              exec("echo 'pow 0' | cec-client -s -d 1", (err, stdout, stderr)=> {
                if (err) {
                  this.logError(err)
                  this.logError("HDMI CEC Error: " + stdout)
                  this.sendSocketNotification("ERROR", "[SCREEN] HDMI CEC command error (mode: " + this.config.mode + ")")
                } else {
                  let responseSh = stdout.trim()
                  var displaySh = responseSh.split("\n")[1].split(" ")[2]
                  if (displaySh == "on") actual = true
                  if (displaySh == "unknown") log("HDMI CEC unknow state")
                  this.resultDisplay(actual,wanted)
                }
              })
              break
            case 5:
            /** dmps linux **/
              exec("xset q | grep Monitor", (err, stdout, stderr)=> {
                if (err) {
                  this.logError("[Display Error] " + err)
                  this.sendSocketNotification("ERROR", "[SCREEN] dpms linux command error (mode: " + this.config.mode + ")")
                }
                else {
                  let responseSh = stdout.trim()
                  var displaySh = responseSh.split(" ")[2]
                  if (displaySh == "On") actual = true
                  this.resultDisplay(actual,wanted)
                }
              })
              break
            case 6:
            /** python script **/
              exec("python monitor.py -s -g="+this.config.gpio, { cwd: this.PathScript }, (err, stdout, stderr)=> {
                if (err) {
                  this.logError("[Display Error] " + err)
                  this.sendSocketNotification("ERROR", "[SCREEN] python relay script error (mode: " + this.config.mode + ")")
                }
                else {
                  let responsePy = stdout.trim()
                  log("Response PY -- Check State: " + responsePy)
                  if (responsePy == 1) actual = true
                  this.resultDisplay(actual,wanted)
                }
              })
              break
            case 7:
            /** python script reverse**/
              exec("python monitor.py -s -g="+this.config.gpio, { cwd: this.PathScript }, (err, stdout, stderr)=> {
                if (err) {
                  this.logError("[Display Error] " + err)
                  this.sendSocketNotification("ERROR", "[SCREEN] python relay script error (mode: " + this.config.mode + ")")
                }
                else {
                  let responsePy = stdout.trim()
                  log("Response PY -- Check State (reverse): " + responsePy)
                  if (responsePy == 0) actual = true
                  this.resultDisplay(actual,wanted)
                }
              })
              break
            case 8:
            /** ddcutil **/
              exec("ddcutil getvcp d6", (err, stdout, stderr)=> {
                if (err) {
                  this.logError(err)
                  this.sendSocketNotification("ERROR", "[SCREEN] ddcutil command error (mode: " + this.config.mode + ")")
                }
                else {
                  let responseSh = stdout.trim()
                  var displaySh = responseSh.split("(sl=")[1]
                  log(responseSh)
                  log(displaySh)
                  if (displaySh == "0x01)") actual = true
                  this.resultDisplay(actual,wanted)
                }
              })
              break
          }
        }
      
        resultDisplay (actual,wanted) {
          log("Display -- Actual: " + actual + " - Wanted: " + wanted)
          this.screen.power = actual
          if (actual && !wanted) this.setPowerDisplay(false)
          if (!actual && wanted) this.setPowerDisplay(true)
        }
      
        async setPowerDisplay (set) {
          log("Display " + (set ? "ON." : "OFF."))
          this.screen.power = set
          this.SendScreenPowerState()
          if (this.screen.awaitBeforeTurnOff && !set) await this.sleep(this.screen.awaitBeforeTurnOffTime)
          // and finally apply rules !
          switch (this.config.mode) {
            case 1:
              if (set) exec("/usr/bin/vcgencmd display_power 1")
              else exec("/usr/bin/vcgencmd display_power 0")
              break
            case 8:
              if (set) exec("ddcutil setvcp d6 1")
              else exec("ddcutil setvcp d6 4")
              break
            case 2:
              if (set) exec("DISPLAY=:0 xset dpms force on")
              else exec("DISPLAY=:0 xset dpms force off")
              break
            case 3:
              if (set) exec("tvservice -p && sudo chvt 6 && sudo chvt 7")
              else exec("tvservice -o")
              break
            case 4:
              if (set) exec("echo 'on 0' | cec-client -s")
              else exec("echo 'standby 0' | cec-client -s")
              break
            case 5:
              if (set) exec("xset dpms force on")
              else exec("xset dpms force off")
              break
            case 6:
              if (set)
                exec("python monitor.py -r=1 -g="+this.config.gpio, { cwd: this.PathScript }, (err, stdout, stderr)=> {
                  if (err) console.log("[SCREEN] err:", err)
                  else log("Relay is " + stdout.trim())
                })
              else
                if (this.config.clearGpioValue) {
                  exec("python monitor.py -r=0 -c -g="+this.config.gpio, {cwd: this.PathScript},(err, stdout, stderr)=> {
                    if (err) console.log("[SCREEN] err:", err)
                    else {
                      log("Relay is " + stdout.trim())
                    }
                  })
                } else {
                  exec("python monitor.py -r=0 -g="+this.config.gpio, {cwd: this.PathScript},(err, stdout, stderr)=> {
                    if (err) console.log("[SCREEN] err:", err)
                    else {
                      log("Relay is " + stdout.trim())
                    }
                  })
                }
              break
            case 7:
              if (set) {
                if (this.config.clearGpioValue) {
                  exec("python monitor.py -r=0 -c -g="+this.config.gpio, {cwd: this.PathScript},(err, stdout, stderr)=> {
                    if (err) console.log("[SCREEN] err:", err)
                    else {
                      log("Relay is " + stdout.trim())
                    }
                  })
                } else {
                  exec("python monitor.py -r=0 -g="+this.config.gpio, {cwd: this.PathScript},(err, stdout, stderr)=> {
                    if (err) console.log("[SCREEN] err:", err)
                    else {
                      log("Relay is " + stdout.trim())
                    }
                  })
                }
              } else {
                exec("python monitor.py -r=1 -g="+this.config.gpio, { cwd: this.PathScript }, (err, stdout, stderr)=> {
                  if (err) console.log("[SCREEN] err:", err)
                  else log("Relay is " + stdout.trim())
                })
              }
              break
          }
        }
      
        state() {
          this.sendSocketNotification("SCREEN_STATE", this.screen)
        }
      
        SendScreenPowerState() {
          this.sendSocketNotification("SCREEN_POWER", this.screen.power)
        }
      
        logError(err) {
          console.error("[SCREEN] " + err)
        }
      
        sleep(ms=1300) {
          return new Promise((resolve) => {
            this.screen.awaitBeforeTurnOffTimer = setTimeout(resolve, ms)
          })
        }
      }
      
      module.exports = SCREEN
      
      
      1 Reply Last reply Reply Quote 0
      • bugsounet
        bugsounet Main Coder last edited by

        Hi @pink-o ,

        Thanks for your purpose, il will inspect it soon 😉

        1 Reply Last reply Reply Quote 0
        • bugsounet
          bugsounet Main Coder last edited by

          Hi, I have just commit your purpose in 1.1.8

          1 Reply Last reply Reply Quote 0
          • Topic has been marked as solved  bugsounet bugsounet 
          • First post
            Last post
          Powered by NodeBB | @bugsounet ©2022