<< return to Vizycam.com

User Tools

Site Tools


wiki:test

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
wiki:test [2021/02/13 13:21]
vizycam
wiki:test [2021/10/16 18:30] (current)
vizycam
Line 1: Line 1:
-====== Module vizypowerboard ======+[[wiki:​running_utilities|utilities]]
  
-This module is used with the Vizy Power Board, which is a printed circuit board that plugs into the Raspberry Pi I/O connector and is included with the Vizy camera. More information about Vizy can be found [[https://​vizycamcam.com|here]].+[[wiki:pinoouts|pinouts]]
  
-===== Variables =====+[[wiki:​ssh|ssh]]
  
-  * **''​%%CHANNEL_5V%%''​** Used with ''​%%VizyPowerBoard.measure()%%''​. +[[wiki:​birdfeeder_app|birdfeeder]]
-  * **''​%%CHANNEL_VIN%%''​** Used with ''​%%VizyPowerBoard.measure()%%''​. +
-  * **''​%%DIPSWITCH_EXT_BUTTON%%''​** Used with ''​%%VizyPowerBoard.dip_switches()%%''​. +
-  * **''​%%DIPSWITCH_MUTE_BUZZER%%''​** Used with ''​%%VizyPowerBoard.dip_switches()%%''​. +
-  * **''​%%DIPSWITCH_NO_BG_LED%%''​** Used with ''​%%VizyPowerBoard.dip_switches()%%''​. +
-  * **''​%%DIPSWITCH_POWER_DEFAULT_OFF%%''​** Used with ''​%%VizyPowerBoard.dip_switches()%%''​. +
-  * **''​%%DIPSWITCH_POWER_DEFAULT_ON%%''​** Used with ''​%%VizyPowerBoard.dip_switches()%%''​. +
-  * **''​%%DIPSWITCH_POWER_PLUG%%''​** Used with ''​%%VizyPowerBoard.dip_switches()%%''​. +
-  * **''​%%DIPSWITCH_POWER_SWITCH%%''​** Used with ''​%%VizyPowerBoard.dip_switches()%%''​. +
-  * **''​%%IO_MODE_HIGH_CURRENT%%''​** Used with ''​%%VizyPowerBoard.io_set_mode()%%''​. +
-  * **''​%%IO_MODE_INPUT%%''​** Used with ''​%%VizyPowerBoard.io_set_mode()%%''​. +
-  * **''​%%IO_MODE_OUTPUT%%''​** Used with ''​%%VizyPowerBoard.io_set_mode()%%''​. +
-  * **''​%%POWER_ON_SOURCE_12V%%''​** Used with ''​%%VizyPowerBoard.power_on_source()%%''​. +
-  * **''​%%POWER_ON_SOURCE_5V%%''​** Used with ''​%%VizyPowerBoard.power_on_source()%%''​. +
-  * **''​%%POWER_ON_SOURCE_ALARM%%''​** Used with ''​%%VizyPowerBoard.power_on_source()%%''​. +
-  * **''​%%POWER_ON_SOURCE_POWER_BUTTON%%''​** Used with ''​%%VizyPowerBoard.power_on_source()%%''​.+
  
-===== Classes =====+[[wiki:​stage|stage]]
  
-<​HTML><​dl></HTML+hello 
-<HTML><dt></​HTML>''​%%VizyPowerBoard(addr=20bus=1)%%''<​HTML><​/dt></HTML+<​HTML>​ 
-<HTML><dd></HTML><HTML><p></HTML>This class may be instantiated by more than one processThe vizy-powerd service instantiates this class and uses it to monitor and control things such as power-off requestsCPU temperaturefan speedetc.\\ +<!doctype html> 
-User programs can also instantiate this class and use its methods simultaneously.<HTML></p></HTML+<html lang="​en"​
-<HTML><p></HTML>Argsaddr (integeroptionaldefault=0x14)I2C address of the board bus (integeroptionaldefault=1)the I2C bus number<HTML></p></HTML+<head> 
-==== Methods ====+<meta charset="​utf-8"​> 
 +<meta name="​viewport"​ content="​width=device-widthinitial-scale=1, minimum-scale=1" ​/> 
 +<meta name="​generator"​ content="​pdoc 0.9.2" ​/> 
 +<title>vizypowerboard API documentation</title> 
 +<meta name="​description"​ content="​This module is used with the Vizy Power Board, which is a printed circuit 
 +board that plugs into the Raspberry Pi I/O connector and is included 
 +with …" ​/> 
 +<link rel="​preload stylesheet"​ as="​style"​ href="​https://​cdnjs.cloudflare.com/​ajax/​libs/​10up-sanitize.css/​11.0.1/​sanitize.min.css"​ integrity="​sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs="​ crossorigin> 
 +<link rel="​preload stylesheet"​ as="​style"​ href="​https://​cdnjs.cloudflare.com/​ajax/​libs/​10up-sanitize.css/​11.0.1/​typography.min.css"​ integrity="​sha256-7l/​o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg="​ crossorigin> 
 +<link rel="​stylesheet preload"​ as="​style"​ href="​https:​//​cdnjs.cloudflare.com/​ajax/​libs/​highlight.js/​10.1.1/​styles/​github.min.css"​ crossorigin> 
 +<​style>:​root{--highlight-color:#​fe9}.flex{display:​flex !important}body{line-height:​1.5em}#​content{padding:​10px}#​sidebar{padding:​15px;​overflow:​hidden}#​sidebar > *:last-child{margin-bottom:​2cm}.http-server-breadcrumbs{font-size:​130%;​margin:​0 0 15px 0}#​footer{font-size:​.75em;​padding:​5px 30px;​border-top:​1px solid #​ddd;​text-align:​right}#​footer p{margin:0 0 0 1em;​display:​inline-block}#​footer p:​last-child{margin-right:​30px}h1,h2,h3,h4,​h5{font-weight:​300}h1{font-size:​2.5em;​line-height:​1.1em}h2{font-size:​1.75em;​margin:​1em 0 .50em 0}h3{font-size:​1.4em;​margin:​25px 0 10px 0}h4{margin:​0;​font-size:​105%}h1:​target,​h2:​target,​h3:​target,​h4:​target,​h5:​target,​h6:​target{background:​var(--highlight-color);​padding:​.2em 0}a{color:#​058;​text-decoration:​none;​transition:​color .3s ease-in-out}a:​hover{color:#​e82}.title code{font-weight:​bold}h2[id^="​header-"​]{margin-top:​2em}.ident{color:#​900}pre code{background:#​f8f8f8;​font-size:​.8em;​line-height:​1.4em}code{background:#​f2f2f1;​padding:​1px 4px;​overflow-wrap:​break-word}h1 code{background:​transparent}pre{background:#​f8f8f8;​border:​0;​border-top:​1px solid #​ccc;​border-bottom:​1px solid #​ccc;​margin:​1em 0;​padding:​1ex}#​http-server-module-list{display:​flex;​flex-flow:​column}#​http-server-module-list div{display:​flex}#​http-server-module-list dt{min-width:​10%}#​http-server-module-list p{margin-top:​0}.toc ul,#​index{list-style-type:​none;​margin:​0;​padding:​0}#​index code{background:​transparent}#​index h3{border-bottom:​1px solid #ddd}#index ul{padding:​0}#​index h4{margin-top:​.6em;​font-weight:​bold}@media (min-width:​200ex){#​index .two-column{column-count:​2}}@media (min-width:​300ex){#​index .two-column{column-count:​3}}dl{margin-bottom:​2em}dl dl:​last-child{margin-bottom:​4em}dd{margin:​0 0 1em 3em}#​header-classes + dl dd{margin-bottom:​3em}dd dd{margin-left:​2em}dd ​p{margin:​10px 0}.name{background:#​eee;​font-weight:​bold;​font-size:​.85em;​padding:​5px 10px;​display:​inline-block;​min-width:​40%}.name:​hover{background:#​e0e0e0}dt:​target .name{background:​var(--highlight-color)}.name ​span:​first-child{white-space:​nowrap}.name.class > span:​nth-child(2){margin-left:​.4em}.inherited{color:#​999;​border-left:​5px solid #​eee;​padding-left:​1em}.inheritance em{font-style:​normal;​font-weight:​bold}.desc h2{font-weight:​400;​font-size:​1.25em}.desc h3{font-size:​1em}.desc dt code{background:​inherit}.source summary,​.git-link-div{color:#​666;​text-align:​right;​font-weight:​400;​font-size:​.8em;​text-transform:​uppercase}.source summary > *{white-space:​nowrap;​cursor:​pointer}.git-link{color:​inherit;​margin-left:​1em}.source pre{max-height:​500px;​overflow:​auto;​margin:​0}.source pre code{font-size:​12px;​overflow:​visible}.hlist{list-style:​none}.hlist li{display:​inline}.hlist li:​after{content:',​\2002'​}.hlist li:​last-child:​after{content:​none}.hlist .hlist{display:​inline;​padding-left:​1em}img{max-width:​100%}td{padding:​0 .5em}.admonition{padding:​.1em .5em;​margin-bottom:​1em}.admonition-title{font-weight:​bold}.admonition.note,​.admonition.info,​.admonition.important{background:#​aef}.admonition.todo,​.admonition.versionadded,​.admonition.tip,​.admonition.hint{background:#​dfd}.admonition.warning,​.admonition.versionchanged,​.admonition.deprecated{background:#​fd4}.admonition.error,​.admonition.danger,​.admonition.caution{background:​lightpink}</style
 +<style media="​screen and (min-width: 700px)"​>@media screen and (min-width:​700px){#​sidebar{width:​35%;​position:​sticky;​top:​0}#​content{width:​70%;​max-width:​100ch;​padding:​3em 4em;​border-left:​1px solid #ddd}pre code{font-size:​1em}.item .name{font-size:​1em}main{display:​flex;​flex-direction:​row-reverse;​justify-content:​flex-end}.toc ul ul,#index ul{padding-left:​1.5em}.toc ​ul > li{margin-top:​.5em}}</style> 
 +<style media="​print">​@media print{#​sidebar h1{page-break-before:always}.source{display:​none}}@media print{*{background:​transparent !important;​color:#​000 !important;​box-shadow:​none !important;​text-shadow:​none !important}a[href]:​after{content:" ​(" attr(href) "​)";​font-size:​90%}a[href][title]:​after{content:​none}abbr[title]:​after{content:"​ (" attr(title) "​)"​}.ir a:after,a[href^="​javascript:"​]:​after,a[href^="#"​]:after{content:""​}pre,blockquote{border:​1px solid #​999;​page-break-inside:​avoid}thead{display:​table-header-group}tr,img{page-break-inside:​avoid}img{max-width:​100% !important}@page{margin:​0.5cm}p,​h2,​h3{orphans:​3;​widows:​3}h1,​h2,​h3,​h4,​h5,​h6{page-break-after:​avoid}}</​style>​ 
 +<script defer src="https://​cdnjs.cloudflare.com/​ajax/​libs/​highlight.js/​10.1.1/​highlight.min.js"​ integrity="​sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8="​ crossorigin>​</script> 
 +<​script>​window.addEventListener('​DOMContentLoaded',​ () => hljs.initHighlighting())</script> 
 +</head
 +<​body>​ 
 +<​main>​ 
 +<article id="​content">​ 
 +<​header>​ 
 +<h1 class="​title">​Module <​code>​vizypowerboard</​code></​h1>​ 
 +</​header>​ 
 +<section id="​section-intro">​ 
 +<​p>​This module is used with the Vizy Power Board, which is a printed circuit 
 +board that plugs into the Raspberry Pi I/O connector and is included 
 +with the Vizy camera. 
 +More information 
 +about Vizy can be found <a href="​https://​vizycamcam.com">​here</​a>​.</​p>​ 
 +<details class="​source">​ 
 +<​summary>​ 
 +<​span>​Expand source code</​span>​ 
 +</​summary>​ 
 +<​pre><​code class="​python">#​ Copyright (C) 2021 Charmed Labs LLC 
 +
 +# begin license header 
 +
 +# This file is part of Vizy Software.  
 +
 +# This source code is provided under the terms of the 
 +# GNU General Public License v2 (http://​www.gnu.org/​licenses/​gpl-2.0.html). 
 +# Those wishing to use this source code, software and/or 
 +# technologies under different licensing terms should contact us at 
 +# [email protected].  
 +
 +# end license header 
 +&#​34;&#​34;&#​34;​ 
 +This module is used with the Vizy Power Board, which is a printed circuit  
 +board that plugs into the Raspberry Pi I/O connector and is included 
 +with the Vizy camera. ​ More information  
 +about Vizy can be found [here](https://​vizycamcam.com). 
 +&#​34;&#​34;&#​34; ​    
 +import smbus 
 +import RPi.GPIO as GPIO 
 +import time 
 +import datetime 
 +import os
  
-<HTML><​dl></​HTML+FILE_VERSION = 1 
-<HTML><​dt></​HTML>''​%%button(self)%%''​<HTML></​dt></​HTML+COMPAT_HW_VERSION = [3, 0] 
-<HTML><​dd></​HTML>​Returns ​''​%%True%%'' ​if the button is being pressed currently, ​''​%%False%%'' ​otherwise.<​HTML></dd></HTML+ 
-<HTML><​dt><​/HTML>''​%%button_pressed(self)%%''​<HTML></​dt></​HTML+ERROR_GENERIC = 255 
-<HTML><dd></HTML>​Returns ​''​%%True%%'' ​if the button was pressed within the last 5 seconds, ​''​%%False%%'' ​otherwise. This is useful if the polling is intermittant or slow, as button presses are not missed (as long as you check at least every 5 seconds!)<​HTML></dd></HTML+ERROR_BUSY = 254 
-<HTML><​dt><​/HTML>''​%%buzzer(self,​ freq, on=250, off=250, count=1, shift=0)%%''​<HTML></dt></HTML+ERROR_READ_ONLY = 253 
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>Emit tones through the buzzer. The ''​%%freq%%'' ​argument sets the frequency of the tone in Hz and the ''​%%on%%'' ​argument sets the length of the tone in milliseconds.<​HTML>​</p></​HTML+ERROR_NOT_SUPPORTED = 252 
-<​HTML>​<p></​HTML>If you wish to emit more than 1 tone, you can set the ''​%%count%%'' ​argument to the desired number.<​HTML>​</p></​HTML+ 
-<HTML><p></HTML>The ''​%%off%%'' ​argument sets the pause between tones in milliseconds. The ''​%%shift%%'' ​argument is a value ranging between -128 and 127 that causes the tones frequency to raise if ''​%%shift%%'' ​is greater than 0, or descend if ''​%%shift%%'' ​is less than 0.<​HTML>​</​p><​/HTML> +EXEC_OFFSET = 0xc0 
-<​code>​ +EXEC_RW = 0x80 
-buzzer(2000,​ 500) # emit a 2000Hz tone for 500ms+EXEC_WRITE = 0x80 
 +EXEC_NVCONFIG = 1 
 +EXEC_AD = 2 
 +EXEC_DA = 3 
 +EXEC_RTC = 16 
 +EXEC_RTC_CALIBRATE = 17 
 + 
 +IO_MODE_INPUT = 0 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.io_set_mode()`.&#​34;&#​34;&#​34;​ 
 +IO_MODE_OUTPUT = 0x80  
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.io_set_mode()`.&#​34;&#​34;&#​34;​ 
 +IO_MODE_HIGH_CURRENT = IO_MODE_OUTPUT | 0x40 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.io_set_mode()`.&#​34;&#​34;&#​34;​ 
 + 
 +DIPSWITCH_EXT_BUTTON = 0x01 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.dip_switches()`.&#​34;&#​34;&#​34;​ 
 +DIPSWITCH_MUTE_BUZZER = 0x02 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.dip_switches()`.&#​34;&#​34;&#​34;​ 
 +DIPSWITCH_NO_BG_LED = 0x04 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.dip_switches()`.&#​34;&#​34;&#​34;​ 
 +DIPSWITCH_POWER_DEFAULT_OFF = 0x00 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.dip_switches()`.&#​34;&#​34;&#​34;​ 
 +DIPSWITCH_POWER_DEFAULT_ON = 0x40 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.dip_switches()`.&#​34;&#​34;&#​34;​ 
 +DIPSWITCH_POWER_SWITCH = 0x80 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.dip_switches()`.&#​34;&#​34;&#​34;​ 
 +DIPSWITCH_POWER_PLUG = 0xc0 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.dip_switches()`.&#​34;&#​34;&#​34;​ 
 + 
 +POWER_ON_SOURCE_ALARM = 0x01 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.power_on_source()`.&#​34;&#​34;&#​34;​ 
 +POWER_ON_SOURCE_POWER_BUTTON = 0x02 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.power_on_source()`.&#​34;&#​34;&#​34;​ 
 +POWER_ON_SOURCE_12V = 0x03 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.power_on_source()`.&#​34;&#​34;&#​34;​ 
 +POWER_ON_SOURCE_5V = 0x04 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.power_on_source()`.&#​34;&#​34;&#​34;​ 
 + 
 +CHANNEL_VIN = 4 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.measure()`.&#​34;&#​34;&#​34;​ 
 +CHANNEL_5V = 5 
 +&#​34;&#​34;&#​34;​Used with `VizyPowerBoard.measure()`.&#​34;&#​34;&#​34;​ 
 + 
 +class VizyPowerBoard:​ 
 +    &#​34;&#​34;&#​34;​ 
 +    This class may be 
 +    instantiated by more than one process. ​ The vizy-powerd service 
 +    instantiates this class and uses it to monitor and control things such  
 +    as power-off requests, CPU temperature,​ fan speed, etc.   
 +    User programs can also instantiate this class and 
 +    use its methods simultaneously. 
 +    &#​34;&#​34;&#​34; ​    
 +    def __init__(self,​ addr=0x14, bus=1): 
 +        &#​34;&#​34;&#​34;​ 
 +        Args: 
 +          addr (integer, optional, default=0x14):​ I2C address of the board 
 +          bus (integer, optional, default=1): the I2C bus number  
 + 
 +        &#​34;&#​34;&#​34;​ 
 +        self.bus = smbus.SMBus(bus) 
 +        self.addr = addr 
 +        hwv = self.hw_version() 
 +        if hwv!=COMPAT_HW_VERSION:​ 
 +            raise RuntimeError(&#​34;​The hardware version of your Vizy Power Board (&#34; + str(hwv[0])+&#​39;​.&#​39;​+str(hwv[1]) + &#34;) is incompatible with this software file (&#34; + str(COMPAT_HW_VERSION[0])+&#​39;​.&#​39;​+str(COMPAT_HW_VERSION[1]) + &#​34;​).&#​34;​) 
 + 
 +    @staticmethod 
 +    def _bcd2decimal(bcd):​ 
 +        tens = (bcd&​amp;​0xf0)&​gt;&​gt;​4 
 +        ones = bcd&​amp;​0x0f 
 +        return tens*10 + ones 
 + 
 +    @staticmethod 
 +    def _decimal2bcd(dec):​ 
 +        tens = int(dec/​10) 
 +        ones = dec%10 
 +        return (tens&​lt;&​lt;​4) | ones 
 + 
 +    @staticmethod 
 +    def _u_int8(i):​ 
 +        i = round(i) 
 +        if i&​gt;​0xff:​ 
 +            return 0xff 
 +        if i&​lt;​0:​ 
 +            return 0 
 +        return i 
 + 
 +    @staticmethod 
 +    def _int8(i): 
 +        i = round(i) 
 +        if i&​gt;​0x7f:​ 
 +            return 0x7f 
 +        if i&​lt;​-0x80:​ 
 +            return 0x80 
 +        if i&​lt;​0:​ 
 +            return 0x100+i 
 +        return i 
 + 
 +    @staticmethod 
 +    def _uint16(i):​ 
 +        i = round(i) 
 +        if i&​gt;​0xffff:​ 
 +            return 0xffff 
 +        if i&​lt;​0:​ 
 +            return 0 
 +        return i 
 + 
 +    def _status(self):​ 
 +        return self.bus.read_i2c_block_data(self.addr,​ 0, 1)[0] 
 + 
 +    def _wait_until_not_busy(self):​ 
 +        while self._status()==ERROR_BUSY:​ 
 +            time.sleep(0.001) 
 + 
 +    def hw_version(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns the major and minor versions of the PCB as a 2-item list. 
 +        &#​34;&#​34;&#​34;​  
 +        return self.bus.read_i2c_block_data(self.addr,​ 1, 2) 
 + 
 +    def fw_version(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns the major, minor and build versions of the firmware as  
 +        a 3-item list. 
 +        &#​34;&#​34;&#​34;​  
 +        return self.bus.read_i2c_block_data(self.addr,​ 3, 3) 
 + 
 +    def resource_url(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns the url of a JSON file that contains information about  
 +        resources, such as the location of the latest version of this code,  
 +        latest firmware, etc. 
 +        &#​34;&#​34;&#​34;​ 
 +        chars = self.bus.read_i2c_block_data(self.addr,​ 6, 32) 
 +        s = &#​39;&#​39;​ 
 +        for c in chars: 
 +            if c==0: # read up to the null character 
 +                break 
 +            s += chr(c) 
 +        return s 
 + 
 +    def uuid(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns a 16-byte unique ID that can be used an a unique 
 +        ID for your Vizy camera. ​ This unique ID is stored on the Vizy Power 
 +        Board and remains constant regardless of firmware upgrades, etc. 
 +        &#​34;&#​34;&#​34;​ 
 +        return self.bus.read_i2c_block_data(self.addr,​ 22, 16) 
 + 
 +    def power_off_requested(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns `True` if Vizy&#​39;​s button is held down for more than 5 seconds 
 +        indicating that the user wishes to initiate safe shutdown and power 
 +        off.  Returns `False` otherwise. 
 + 
 +        This is used by the vizy-powerd service.  
 +        &#​34;&#​34;&#​34;​ 
 +        button = self.bus.read_i2c_block_data(self.addr,​ 38, 1) 
 +        if button[0]==0x0f:​ 
 +            return True 
 +        else: 
 +            return False 
 + 
 +    def power_off(self,​ t=5000): 
 +        &#​34;&#​34;&#​34;​ 
 +        Powers Vizy off. The `t` argument specifies how long  
 +        to wait before turning off (specified in milliseconds). ​ The  
 +        vizy-powerd service calls this upon shutdown. 
 +        &#​34;&#​34;&#​34;​ 
 +        self.bus.write_i2c_block_data(self.addr,​ 38, [0x1f, int(t/​100)]) 
 + 
 +    def power_on_alarm_date(self,​ datetime_=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        If you wish to power off your Vizy and have it &#​34;​wake up&#34; at a 
 +        specified time and date, call this method with the desired 
 +        datetime object and initiate a shutdown. (e.g. `sudo shutdown now`). 
 + 
 + 
 +        The code below tells Vizy to turn on on December 2, 2022, 11:18am. 
 + 
 +            import vizypowerboard as vpb 
 +            from datetime import datetime 
 +            v = vpb.VizyPowerBoard() 
 +            d=datetime(year=2022,​ month=12, day=2, hour=11, minute=18, second=0) 
 +            v.power_on_alarm_date(d) 
 + 
 +        Args: 
 +          datetime_ (datetime, optional, default=None):​ `datetime` object that 
 +            specifies the date/time to &#​34;​wake up&#34; (turn on). 
 + 
 +        Returns: 
 +          Calling without a datetime object returns a `datetime` object  
 +          reflecting the active alarm time.  If there is no active alarm, 
 +          `None` is returned. 
 +            
 +        Notes: 
 +          * Once setting the alarm date, Vizy will retain it even if Vizy loses 
 +          power for extended periods of time. 
 +          * If the alarm expires while Vizy is on, Vizy will emit a buzzer tone 
 +          and remain on. 
 +          * If the alarm expires while Vizy is off (but plugged into and 
 +          receiving power), Vizy will turn on. 
 +          * If the alarm expires while Vizy is unplugged from (or not receiving) 
 +          power, Vizy will turn on as soon as it receives power. ​  
 +        &#​34;&#​34;&#​34;​ 
 +        if datetime_ is None: 
 +            t = self.bus.read_i2c_block_data(self.addr,​ 41, 6) 
 +            if t[5]==0: 
 +                return None 
 +            return datetime.datetime(year=self._bcd2decimal(t[5])+2016,​ month=self._bcd2decimal(t[4]),​ day=self._bcd2decimal(t[3]),​ hour=self._bcd2decimal(t[2]),​ minute=self._bcd2decimal(t[1]),​ second=self._bcd2decimal(t[0])) 
 +        t = [self._decimal2bcd(datetime_.second),​ self._decimal2bcd(datetime_.minute),​ self._decimal2bcd(datetime_.hour),​ self._decimal2bcd(datetime_.day),​ self._decimal2bcd(datetime_.month),​ self._decimal2bcd(datetime_.year-2016)] 
 +        self.bus.write_i2c_block_data(self.addr,​ 41, t) 
 +     
 + 
 +    def power_on_alarm_seconds(self,​ seconds=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Allows you to specify a power on alarm in seconds in the future.  
 +        For example, if you wish for Vizy to turn back on in 5 minutes, you 
 +        would call `power_on_alarm_seconds(300)` and then initiate a shutdown. 
 +        See `VizyPowerBoard.power_on_alarm_date()` for more information about the power on  
 +        alarm. 
 + 
 +        Args: 
 +          seconds (integer, optional, default=None):​ Number of seconds in the 
 +            future you wish Vizy to turn on in. 
 + 
 +        Returns: 
 +          Calling this method without arguments returns the number of seconds 
 +          until the alarm expires. ​ If no alarm is pending, `None` is returned. 
 +        &#​34;&#​34;&#​34;​ 
 +        if seconds is None: 
 +            pod = self.power_on_alarm_date() 
 +            if pod is None: 
 +                return None 
 +            diff = pod - self.rtc() 
 +            return diff.days*86400+diff.seconds  
 +        # Add seconds to current time and set power on alarm     
 +        self.power_on_alarm_date(self.rtc()+datetime.timedelta(seconds=seconds)) 
 + 
 +    def power_on_source(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns the source of what turned on Vizy for the current power cycle. 
 +        It is one of either: 
 + 
 +        * POWER_ON_SOURCE_ALARM,​ indicates that Vizy was powered on 
 +        by the power on alarm expiring. ​ See power_on_alarm_date() and 
 +        power_on_alarm_seconds(). 
 +        * POWER_ON_SOURCE_POWER_BUTTON,​ indicates that Vizy was powered  
 +        on by someone pressing the button. 
 +        * POWER_ON_SOURCE_12V = indicates that Vizy was powered on 
 +        by power being applied to 12V power input. ​ This only applies if the 
 +        dip switch power mode allows powering on by plugging in power via the 
 +        12V power input. 
 +        * POWER_ON_SOURCE_5V,​ indicates that Vizy was powered on by applying 
 +        power to the Raspberry Pi&#​39;​s USB-C power input. 
 +        &#​34;&#​34;&#​34;​ 
 +        source = self.bus.read_i2c_block_data(self.addr,​ 40, 1)[0] 
 +        return source 
 + 
 +    def button(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns `True` if the button is being pressed currently, `False` otherwise. 
 +        &#​34;&#​34;&#​34;​ 
 +        button = self.bus.read_i2c_block_data(self.addr,​ 47, 1) 
 +        if button[0]&​amp;​0x02:​ 
 +            return True 
 +        else: 
 +            return False 
 + 
 +    def button_pressed(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns `True` if the button was pressed within the last 5 seconds, 
 +        `False` otherwise. ​ This is useful if the polling is intermittant or 
 +        slow, as button presses are not missed (as long as you check at least 
 +        every 5 seconds!) 
 +        &#​34;&#​34;&#​34;​ 
 +        button = self.bus.read_i2c_block_data(self.addr,​ 47, 1) 
 +        if button[0]&​amp;​0x01:​ 
 +            # Reset bit 
 +            self.bus.write_i2c_block_data(self.addr,​ 47, [0]) 
 +            return True 
 +        else: 
 +            return False 
 + 
 +    def vcc12(self, state=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        If `state` is `True`, the 12V output on Vizy&#​39;​s I/O connector (pin 2) will be enabled and output 12V.  If `state` is `False`, the 12V output 
 +        will be disabled. ​ Calling without arguments returns its current state. 
 +        &#​34;&#​34;&#​34;​  
 +        config = self.bus.read_i2c_block_data(self.addr,​ 48, 1) 
 +        if state is None: 
 +            return True if config&​amp;​0x01 else False 
 +        if state: 
 +            config[0] |= 0x01 
 +        else: 
 +            config[0] &amp;= ~0x01 
 + 
 +        self.bus.write_i2c_block_data(self.addr,​ 48, config) 
 + 
 +    def vcc5(self, state=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        If `state` is `True`, the 5V output on Vizy&#​39;​s I/O connector (pin 3) will 
 +        be enabled and output 5V.  If `state` is `False`, the 5V output will be 
 +        disabled. ​ Calling without arguments returns its current state. 
 +        &#​34;&#​34;&#​34;​  
 +        if state is None: 
 +            return True if config&​amp;​0x02 else False 
 +        if state: 
 +            config[0] |= 0x02 
 +        else: 
 +            config[0] &amp;= ~0x02 
 + 
 +        self.bus.write_i2c_block_data(self.addr,​ 48, config) 
 + 
 +    def led(self, r=0, g=0, b=0, flashes=0, repeat=False,​ atten=255, on=100, off=100, pause=200):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Controls the RGB LED in one of several modes: 
 + 
 +        * **Continuous**:​ just setting `r`, `g`, and `b` will set set the LED color 
 +        and turn it on continuously. ​ `r`, `g`, and `b` values range between 0  
 +        and  255. 
 + 
 +                led(255, 0, 0)   # turn on LED, red color 
 +                led(255, 255, 0) # turn on LED, yellow color 
 +                led(0, 0, 255)   # turn on LED, blue color 
 +                led(0, 0, 0)     # turn off LED 
 + 
 +        * **Flashes**:​ setting the `flashes` value to a non-zero value will 
 +        cause the LED to flash the indicated number of times. ​ You can also 
 +        specify the `on` and `off` arguments to indicate the amount of time  
 +        the LED is on and off for each flash (specified in milliseconds). 
 + 
 +                led(0, 0, 255, 3)  # flash blue 3 times (then stop) 
 +                led(0, 0, 255, 3, on=500, off=500) ​ # flash blue 3 times, much more slowly 
 + 
 +        * **Repeated flashes**: setting the `repeat` argument to `True`  
 +        will cause the indicated flash pattern to repeat forever. ​ You can 
 +        modify the pause time between flash sequences by setting `pause` 
 +        (milliseconds). 
 + 
 +                led(0, 0, 255, 3, True, pause=500) ​ # flash blue 3 times, pause, then repeat 
 +                led(0, 0, 255, repeat=True,​ on=500, off=500)` ​ # flash blue forever 
 + 
 +        * **Flashing with attenuation**:​ you can also set the `atten`  
 +        argument to make the LED to turn on and off slowly, like an 
 +        incandescent light. ​ The value is the rate of change, so lower values 
 +        cause the LED color to change more slowly.  
 + 
 +                led(0, 0, 255, repeat=True,​ atten=10, on=500, off=500) # flash blue forever, but turn on and turn off very slowly 
 +        &#​34;&#​34;&#​34;​ 
 +        on = self._u_int8(on/​10) 
 +        off = self._u_int8(off/​10) 
 +        pause = self._u_int8(pause/​10) 
 +        if flashes==0:​ 
 +            mode = 0 
 +        if repeat: 
 +            mode = 0x02 
 +        else: 
 +            mode = 0x01 
 +        self.bus.write_i2c_block_data(self.addr,​ 49, [mode, self._u_int8(r),​ self._u_int8(g),​ self._u_int8(b),​ 
 +            on, off, self._u_int8(flashes),​ pause, self._u_int8(atten)]) 
 + 
 +    def led_unicorn(self,​ speed=10):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        This causes the LED to change color in succession: red, orange, yellow,  
 +        green, cyan, blue, violet and then repeat again. ​ The `speed` argument  
 +        ranges between 0 and 10.  For example, a `speed` of 0 causes the color  
 +        to change once every couple of seconds. ​ A `speed` of 10 causes the color to change about 6 times per second. 
 +        &#​34;&#​34;&#​34;​ 
 +        if speed&​gt;​10:​ 
 +            speed = 10 
 +        elif speed&​lt;​0:​ 
 +            speed = 0 
 + 
 +        on = self._u_int8(10 + (10-speed)*140/​10) 
 +        atten = self._u_int8(3 + speed*47/​10) ​    
 +        self.bus.write_i2c_block_data(self.addr,​ 49, [0x08, 0, 0, 0, on, 0, 0, 0, atten]) 
 + 
 +    def led_background(self,​ r=-1, g=-1, b=-1): 
 +        &#​34;&#​34;&#​34;​ 
 +        The &#​34;​background&#​34;​ LED color is the color of the LED when the LED is  
 +        turned &#​34;​off&#​34;​. ​ It is used by system programs such as vizy-powerd to 
 +        indicate Vizy&#​39;​s system state such as, booting (yellow), finished 
 +        booting (green), running server (blue), etc.  Note, the background 
 +        color does not influence the LED colors set by calls to led(). 
 + 
 +        Calling led_background() without arguments returns the current  
 +        background color r, g, and b values in a list.  
 + 
 +            led_background(48,​ 48, 0)  # set background color to yellow 
 +            led(0, 255, 0)  # turn on LED, green (as expected) 
 +            led(0, 0, 0)  # turn LED off, and restore background color (yellow as set previously) ​    
 +        &#​34;&#​34;&#​34;​ 
 +        if r==-1: 
 +            return self.bus.read_i2c_block_data(self.addr,​ 58, 3) 
 +        self.bus.write_i2c_block_data(self.addr,​ 58, [self._u_int8(r),​ self._u_int8(g),​ self._u_int8(b)]) 
 +  
 + 
 +    def buzzer(self,​ freq, on=250, off=250, count=1, shift=0): 
 +        &#​34;&#​34;&#​34;​ 
 +        Emit tones through the buzzer. ​ The `freq` argument sets the frequency  
 +        of the tone in Hz and the `on` argument sets the length of the tone in 
 +        milliseconds. ​  
 + 
 +        If you wish to emit more than 1 tone, you can set the 
 +        `count` argument to the desired number. ​  
 + 
 +        The `off` argument sets  
 +        the pause between tones in milliseconds. ​ The `shift` argument is a 
 +        value ranging between -128 and 127 that causes the tone&#​39;​s frequency to 
 +        raise if `shift` is greater than 0, or descend if `shift` is less  
 +        than 0. 
 + 
 +            buzzer(2000,​ 500) # emit a 2000Hz tone for 500ms 
 +            buzzer(1000,​ count=3) # emit a 1000Hz tone 3 times    
 +            buzzer(1000,​ 500, 100, 3) # emit a longer 1000Hz tone 3 times 
 +            buzzer(500, 250, 0, 10, 50) # emit 10 warbling tones like a siren 
 +        &#​34;&#​34;&#​34;​ 
 +        freq = self._uint16(freq) 
 +        f0 = freq&​amp;​0xff 
 +        f1 = (freq&​gt;&​gt;​8)&​amp;​0xff 
 +        self.bus.write_i2c_block_data(self.addr,​ 61, [0, f0, f1, self._u_int8(on/​10),​ self._u_int8(off/​10),​  
 +            self._u_int8(count),​ self._int8(shift)]) 
 + 
 + 
 +    def io_set_mode(self,​ bit, mode=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Sets or gets the io mode of the given bit.  The `bit` argument ranges 
 +        between ​ 0 and 3 and corresponds to pins 4 through 7 on Vizy&#​39;​s IO 
 +        connector. Calling this method with no mode argument returns the mode 
 +        of the given bit, otherwise, the `mode` argument can be one of  
 +        the following:​ 
 + 
 +        * IO_MODE_INPUT,​ sets the bit to high impedance input mode with  
 +        a weak pull-up resistor to 3.3V.  The input voltage can range between 
 +        0 and Vin where Vin is the supply voltage. ​ Voltages lower than 1V  
 +        read as logic 0 via `VizyPowerBoard.io_bits()`. ​ Voltages higher  
 +        than 1V are read as logic 1. 
 +        * IO_MODE_OUTPUT,​ sets the bit to output mode.  If the bit is set to 
 +        logic 0 via `VizyPowerBoard.io_bits()`,​ the output voltage is 0V.   
 +        If the bit is set to logic 1, the output voltage is 3.3V.  In this mode, each bit can source and sink 5mA.   
 +        * IO_MODE_HIGH_CURRENT,​ sets the bit to a special high current mode 
 +        that allows the bit to sink as much as 1000mA, when the bit  
 +        set to logic 0 via `VizyPowerBoard.io_bits()`. ​ Otherwise, this mode 
 +        behaves exactly as IO_MODE_OUTPUT. ​    
 +        &#​34;&#​34;&#​34;​ 
 +        if mode is None: 
 +            return self.bus.read_i2c_block_data(self.addr,​ 68+bit, 1)[0] 
 +        if bit==2: 
 +            # set GPIO14 (UART TXD) as input so it doesn&#​39;​t conflict 
 +            GPIO.setwarnings(False) 
 +            GPIO.setmode(GPIO.BOARD) 
 +            GPIO.setup(8,​ GPIO.IN) 
 +        self.bus.write_i2c_block_data(self.addr,​ 68+bit, [self._u_int8(mode)]) 
 + 
 +    def io_bits(self,​ bits=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Sets or gets the logic state of the IO bits 0 through 3, corresponding 
 +        to pins 4 through 7 on Vizy&#​39;​s IO connector. ​ The `bits` argument ranges 
 +        between 0 and 15 as it is a binary representation of the logic state 
 +        of the 4 IO bits.  If the `bits` argument isn&#​39;​t specified, the logic 
 +        state of the 4 bits are returned. 
 + 
 +            io_bits(1) ​  # set IO bit 0 to logic 1 and bits 1, 2, 3 to logic 0 
 +            io_bits(10) ​ # set IO bits 1 and 3 to logic 1 and bits 0 and 2 to logic 0 
 +            bits = io_bits() ​ # get logic state of IO bits 
 +            io_bits(io_bits()|1) ​ # set IO bit 0 to logic 1, leave bits 1, 2, 3 unchanged.  
 +        &#​34;&#​34;&#​34;​ 
 +        if bits is None: 
 +            return self.bus.read_i2c_block_data(self.addr,​ 72, 1) 
 +        self.bus.write_i2c_block_data(self.addr,​ 72, [bits]) 
 + 
 + 
 +    def ir_filter(self,​ state=None, duration=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Actuates the electro-mechanical IR-cut filter on Vizy&#​39;​s camera. ​ Vizy 
 +        uses a CMOS sensor which is very sensitive to IR light. ​ IR light can  
 +        adversely affect color fidelity during the daytime so an IR-cut filter 
 +        is used to block the IR light (`state`=True). ​ During nighttime IR light 
 +        is typically used as a discreet method of illumination and the IR-cut 
 +        filter is removed (`state`=False). ​ If the `state` argument is `True`, 
 +        the filter is actuated in place (and will stay there) until another 
 +        call is made with the state argument set to `False` (in which case the 
 +        IR-cut filter will be removed). ​  
 + 
 +        The `duration` argument is optional and 
 +        controls how long (in milliseconds) the actuation coil receives power. 
 + 
 +        Calling this method without arguments returns the state of IR-cut 
 +        filter. 
 +        &#​34;&#​34;&#​34;​ 
 +        if state is None: 
 +            return True if self.bus.read_i2c_block_data(self.addr,​ 73, 1)[0] else False 
 +        data = [1] if state else [0] 
 +        if duration is not None: 
 +            data.append(int(duration/​10)) 
 +        self.bus.write_i2c_block_data(self.addr,​ 73, data) 
 + 
 +    def fan(self, speed=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Set or get the fan speed. ​ The `speed` argument can range between 0  
 +        and 12 where 0 is off and 12 is maximum speed. ​ The fan speed  
 +        is typically regulated automatically by vizy-powerd. 
 + 
 +        Calling this method without arguments returns the current fan speed. ​  
 +        &#​34;&#​34;&#​34;​ 
 +        if speed is None: 
 +            return self.bus.read_i2c_block_data(self.addr,​ 75, 1)[0] 
 +        self.bus.write_i2c_block_data(self.addr,​ 75, [self._u_int8(speed)]) 
 +        
 + 
 +    def rtc(self, datetime_=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Set or get the real-time clock time/​date. ​ The Vizy power board has a  
 +        battery-backed real-time clock that keeps track of time/date, power  
 +        alarms, etc. even while Vizy is receiving no power. ​ Passing in a 
 +        datetime object sets the time/​date. ​  
 + 
 +        Calling this method with no 
 +        arguments returns a datetime object representing the current  
 +        date/time.  
 + 
 +        For example, the code below sets the date to December 2, 2020, 11:18am: 
 + 
 +            from datetime import datetime 
 +            import vizypowerboard as vpb 
 +            v = vpb.VizyPowerBoard() 
 +            t = datetime(year=2020,​ month=12, day=2, hour=11, minute=18, second=0) 
 +            v.rtc(t) 
 +        &#​34;&#​34;&#​34;​ 
 +        if datetime_ is None: 
 +            # Initiate RTC retrieval. 
 +            self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC]) 
 +            # Wait until it&#​39;​s ready. 
 +            self._wait_until_not_busy() 
 + 
 +            t = self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 8) 
 +            return datetime.datetime(year=self._bcd2decimal(t[7])+2016,​ month=self._bcd2decimal(t[6]),​ day=self._bcd2decimal(t[4]),​ hour=self._bcd2decimal(t[3]),​ minute=self._bcd2decimal(t[2]),​ second=self._bcd2decimal(t[1])) 
 +  
 +        t = [EXEC_RTC|EXEC_WRITE,​ 0, self._decimal2bcd(datetime_.second),​ self._decimal2bcd(datetime_.minute),​ self._decimal2bcd(datetime_.hour),​ self._decimal2bcd(datetime_.day),​ 0, self._decimal2bcd(datetime_.month),​ self._decimal2bcd(datetime_.year-2016)] 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ t) 
 +        self._wait_until_not_busy() 
 + 
 +    def dip_switches(self,​ val=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Set or get the (virtual) DIP switch state. ​ The DIP switches are a set  
 +        of &#​34;​switches&#​34;​ that allow you to control Vizy&#​39;​s power-on or power-off 
 +        behavior. ​ Once they are set, they will retain the setting even if  
 +        power is removed.  
 +        The switches are a set of values that can be ORed together: 
 + 
 +        * DIPSWITCH_EXT_BUTTON,​ used to set external/​remote power button,  
 +        e.g. with outdoor enclosure. ​ Default disabled. 
 +        * DIPSWITCH_MUTE_BUZZER,​ used to mute the buzzer. ​ Default disabled. 
 +        * DIPSWITCH_NO_BG_LED,​ used to disable the background LED, which is  
 +        normally set to yellow upon power up.  Default disabled. 
 +        * DIPSWITCH_POWER_DEFAULT_OFF,​ if this power mode is set and you  
 +        plug in power via the 12V power input, Vizy will remain off by default 
 +        until you press the button to power Vizy on.  And if power is 
 +        interrupted while Vizy is on, *Vizy will turn off*.  If power is 
 +        interrupted while Vizy is off, Vizy will remain off.  This is the 
 +        default power mode. 
 +        * DIPSWITCH_POWER_DEFAULT_ON,​ if this power mode is set and you  
 +        plug in power via the 12V power input, Vizy will turn on by default 
 +        without pressing the button. ​ And if power is interrupted while Vizy 
 +        is on, Vizy will reset, but remain on.  If power is interrupted while 
 +        Vizy is off, *Vizy will turn on*.  Default disabled. 
 +        * DIPSWITCH_POWER_SWITCH,​ if this power mode is set and you plug in 
 +        power via the 12V power input, Vizy will remain off (as in 
 +        DIPSWITCH_POWER_DEFAULT_OFF mode), unless power was  
 +        removed while Vizy was on.  In this case Vizy will turn on when you 
 +        (re)apply power. ​ If power is interrupted while Vizy is off, Vizy  
 +        will remain off.  This behavior is similar to the behavior of a real 
 +        power switch in that it retains the power &#​34;​state&#​34;​ (on or off) and acts 
 +        accordingly. ​ Default disabled. 
 +        * DIPSWITCH_POWER_PLUG,​ if this power mode is set Vizy will remain 
 +        powered on as long as it receives power through the 12V power plug,  
 +        and you will not be able to turn off Vizy via button or software as 
 +        long as it&#​39;​s plugged in and receiving power. ​ Default disabled. 
 +         
 +        For example:  
 + 
 +            dip_switches(DIPSWITCH_EXT_BUTTON | DIPSWITCH_POWER_SWITCH) # set external power button and power switch mode 
 +        &#​34;&#​34;&#​34;​ 
 +        if val is None: 
 +            self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_NVCONFIG]) 
 +            # Wait until it&#​39;​s ready. 
 +            self._wait_until_not_busy() 
 +            return self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 1)[0] 
 + 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_NVCONFIG|EXEC_WRITE,​ self._u_int8(val)]) 
 +        self._wait_until_not_busy() 
 + 
 +    def rtc_adjust(self,​ val=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Set or get the real-time clock adjustment. ​ Vizy&#​39;​s real-time clock  
 +        crystal has an accuracy of 20ppm, which means that it can lose or gain  
 +        up to 20 seconds for every 1 million elapsed seconds. ​ Normally, this 
 +        isn&#​39;​t an issue, but if Vizy spends a lengthy period of time (months) 
 +        without Internet access, it could lose or gain minutes, which  
 +        depending on the application could be significant. The adjustment 
 +        value can offset this inaccuracy. ​ The `val` argument can range  
 +        between -128 and 127 and has a multiplier of 2.170 ppm.   
 + 
 +        For example,  
 +        if the RTC is gaining 10 seconds every 1 million seconds, you would  
 +        call `rtc_adjust(-5)`. ​ If the RTC is losing 10 seconds every million 
 +        seconds you would call `rtc_adjust(5)`. 
 +         
 +        The adjustment value is retained by the real-time clock even when  
 +        Vizy&#​39;​s power is removed.  
 +        &#​34;&#​34;&#​34;​ 
 +        if val is None: 
 +            self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC_CALIBRATE]) 
 +            # Wait until it&#​39;​s ready. 
 +            self._wait_until_not_busy() 
 +            return self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 1)[0] 
 + 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC_CALIBRATE|EXEC_WRITE,​ self._int8(val)]) 
 +        self._wait_until_not_busy() 
 + 
 + 
 +    def measure(self,​ channel): 
 +        &#​34;&#​34;&#​34;​ 
 +        Get the voltage values of various channels. ​ The returned value is  
 +        the voltage measured (in Volts) of the given channel. ​ The `channel` 
 +        argument can be one of the following:​ 
 + 
 +        * CHANNEL_VIN,​ this channel measures the voltage present at the 12V 
 +        power input. 
 +        * CHANNEL_5V, this channel measures the voltage present at the 5V 
 +        voltage rail provided to the Raspberry Pi. 
 +        &#​34;&#​34;&#​34; ​  
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_AD, self._u_int8(channel)]) 
 +        # Wait until it&#​39;​s ready. 
 +        self._wait_until_not_busy() 
 +        val = self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+2,​ 2) 
 +        return (val[1]*0x100 + val[0])/​1000 
 + 
 + 
 +    def rtc_set_system_datetime(self,​ datetime_=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        A convenience method that sets the system time/date based on the  
 +        real-time time/​date. ​ This is called by vizy-powerd upon power-up.  
 +        &#​34;&#​34;&#​34;​ 
 +        if os.geteuid()!=0:​ 
 +            raise PermissionError(&#​34;​You need root permission to set the time/​date.&#​34;​) 
 +        if datetime_ is None: 
 +            datetime_ = self.rtc() 
 +        s = datetime_.isoformat() 
 +        os.system(f&#​34;​sudo date -s {s}&#​34;​)</code></​pre>​ 
 +</​details>​ 
 +</​section>​ 
 +<​section>​ 
 +</​section>​ 
 +<​section>​ 
 +<h2 class="​section-title"​ id="​header-variables">​Global variables</​h2>​ 
 +<dl> 
 +<dt id="​vizypowerboard.CHANNEL_5V"><​code class="​name">​var <span class="​ident">​CHANNEL_5V</span></​code></​dt
 +<dd> 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.measure"​ href="#​vizypowerboard.VizyPowerBoard.measure">​VizyPowerBoard.measure()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<​dt ​id="​vizypowerboard.CHANNEL_VIN"​><code class="​name">​var <span class="​ident">​CHANNEL_VIN</span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.measure"​ href="#​vizypowerboard.VizyPowerBoard.measure">​VizyPowerBoard.measure()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.DIPSWITCH_EXT_BUTTON"><​code class="​name">​var <span class="​ident">​DIPSWITCH_EXT_BUTTON</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.dip_switches"​ href="#​vizypowerboard.VizyPowerBoard.dip_switches">​VizyPowerBoard.dip_switches()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.DIPSWITCH_MUTE_BUZZER"><​code class="​name">​var <span class="​ident">​DIPSWITCH_MUTE_BUZZER</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.dip_switches"​ href="#​vizypowerboard.VizyPowerBoard.dip_switches">​VizyPowerBoard.dip_switches()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.DIPSWITCH_NO_BG_LED"><​code class="​name">​var <span class="​ident">​DIPSWITCH_NO_BG_LED</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.dip_switches"​ href="#​vizypowerboard.VizyPowerBoard.dip_switches">​VizyPowerBoard.dip_switches()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.DIPSWITCH_POWER_DEFAULT_OFF"><​code class="​name">​var <span class="​ident">​DIPSWITCH_POWER_DEFAULT_OFF</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.dip_switches"​ href="#​vizypowerboard.VizyPowerBoard.dip_switches">​VizyPowerBoard.dip_switches()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.DIPSWITCH_POWER_DEFAULT_ON"><​code class="​name">​var <span class="​ident">​DIPSWITCH_POWER_DEFAULT_ON</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.dip_switches"​ href="#​vizypowerboard.VizyPowerBoard.dip_switches">​VizyPowerBoard.dip_switches()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.DIPSWITCH_POWER_PLUG"><​code class="​name">​var <span class="​ident">​DIPSWITCH_POWER_PLUG</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.dip_switches"​ href="#​vizypowerboard.VizyPowerBoard.dip_switches">​VizyPowerBoard.dip_switches()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.DIPSWITCH_POWER_SWITCH"><​code class="​name">​var <span class="​ident">​DIPSWITCH_POWER_SWITCH</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.dip_switches"​ href="#​vizypowerboard.VizyPowerBoard.dip_switches">​VizyPowerBoard.dip_switches()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.IO_MODE_HIGH_CURRENT"><​code class="​name">​var <span class="​ident">​IO_MODE_HIGH_CURRENT</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.io_set_mode"​ href="#​vizypowerboard.VizyPowerBoard.io_set_mode">​VizyPowerBoard.io_set_mode()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.IO_MODE_INPUT"><​code class="​name">​var <span class="​ident">​IO_MODE_INPUT</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.io_set_mode"​ href="#​vizypowerboard.VizyPowerBoard.io_set_mode">​VizyPowerBoard.io_set_mode()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.IO_MODE_OUTPUT"><​code class="​name">​var <span class="​ident">​IO_MODE_OUTPUT</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.io_set_mode"​ href="#​vizypowerboard.VizyPowerBoard.io_set_mode">​VizyPowerBoard.io_set_mode()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.POWER_ON_SOURCE_12V"><​code class="​name">​var <span class="​ident">​POWER_ON_SOURCE_12V</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.power_on_source"​ href="#​vizypowerboard.VizyPowerBoard.power_on_source">​VizyPowerBoard.power_on_source()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.POWER_ON_SOURCE_5V"><​code class="​name">​var <span class="​ident">​POWER_ON_SOURCE_5V</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.power_on_source"​ href="#​vizypowerboard.VizyPowerBoard.power_on_source">​VizyPowerBoard.power_on_source()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.POWER_ON_SOURCE_ALARM"><​code class="​name">​var <span class="​ident">​POWER_ON_SOURCE_ALARM</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.power_on_source"​ href="#​vizypowerboard.VizyPowerBoard.power_on_source">​VizyPowerBoard.power_on_source()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.POWER_ON_SOURCE_POWER_BUTTON"><​code class="​name">​var <span class="​ident">​POWER_ON_SOURCE_POWER_BUTTON</​span></​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Used with <​code><​a title="​vizypowerboard.VizyPowerBoard.power_on_source"​ href="#​vizypowerboard.VizyPowerBoard.power_on_source">​VizyPowerBoard.power_on_source()</​a></​code>​.</​p></​div>​ 
 +</​dd>​ 
 +</​dl>​ 
 +</​section>​ 
 +<​section>​ 
 +</​section>​ 
 +<​section>​ 
 +<h2 class="​section-title"​ id="​header-classes">​Classes</​h2>​ 
 +<​dl>​ 
 +<dt id="​vizypowerboard.VizyPowerBoard"><​code class="​flex name class">​ 
 +<​span>​class <span class="​ident">​VizyPowerBoard</​span></​span>​ 
 +<​span>​(</​span><​span>​addr=20,​ bus=1)</​span>​ 
 +</​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​This class may be 
 +instantiated by more than one process. 
 +The vizy-powerd service 
 +instantiates this class and uses it to monitor and control things such 
 +as power-off requests, CPU temperature,​ fan speed, etc.<​br>​ 
 +User programs can also instantiate this class and 
 +use its methods simultaneously.</​p>​ 
 +<h2 id="​args">​Args</​h2>​ 
 +<​dl>​ 
 +<​dt><​strong><​code>​addr</​code></​strong>​ :&​ensp;<​code>​integer</​code>,​ optional, default=<​code>​0x14</​code></​dt>​ 
 +<​dd>​I2C address of the board</​dd>​ 
 +<​dt><​strong><​code>​bus</​code></​strong>​ :&​ensp;<​code>​integer</​code>,​ optional, default=<​code>​1</​code></​dt>​ 
 +<​dd>​the I2C bus number</​dd>​ 
 +</​dl></​div>​ 
 +<details class="​source">​ 
 +<​summary>​ 
 +<​span>​Expand source code</​span>​ 
 +</​summary>​ 
 +<​pre><​code class="​python">​class VizyPowerBoard:​ 
 +    &#​34;&#​34;&#​34;​ 
 +    This class may be 
 +    instantiated by more than one process. ​ The vizy-powerd service 
 +    instantiates this class and uses it to monitor and control things such  
 +    as power-off requests, CPU temperature,​ fan speed, etc.   
 +    User programs can also instantiate this class and 
 +    use its methods simultaneously. 
 +    &#​34;&#​34;&#​34; ​    
 +    def __init__(self,​ addr=0x14, bus=1): 
 +        &#​34;&#​34;&#​34;​ 
 +        Args: 
 +          addr (integer, optional, default=0x14):​ I2C address of the board 
 +          bus (integer, optional, default=1): the I2C bus number  
 + 
 +        &#​34;&#​34;&#​34;​ 
 +        self.bus = smbus.SMBus(bus) 
 +        self.addr = addr 
 +        hwv = self.hw_version() 
 +        if hwv!=COMPAT_HW_VERSION:​ 
 +            raise RuntimeError(&#​34;​The hardware version of your Vizy Power Board (&#34; + str(hwv[0])+&#​39;​.&#​39;​+str(hwv[1]) + &#34;) is incompatible with this software file (&#34; + str(COMPAT_HW_VERSION[0])+&#​39;​.&#​39;​+str(COMPAT_HW_VERSION[1]) + &#​34;​).&#​34;​) 
 + 
 +    @staticmethod 
 +    def _bcd2decimal(bcd):​ 
 +        tens = (bcd&​amp;​0xf0)&​gt;&​gt;​4 
 +        ones = bcd&​amp;​0x0f 
 +        return tens*10 + ones 
 + 
 +    @staticmethod 
 +    def _decimal2bcd(dec):​ 
 +        tens = int(dec/​10) 
 +        ones = dec%10 
 +        return (tens&​lt;&​lt;​4) | ones 
 + 
 +    @staticmethod 
 +    def _u_int8(i):​ 
 +        i = round(i) 
 +        if i&​gt;​0xff:​ 
 +            return 0xff 
 +        if i&​lt;​0:​ 
 +            return 0 
 +        return i 
 + 
 +    @staticmethod 
 +    def _int8(i): 
 +        i = round(i) 
 +        if i&​gt;​0x7f:​ 
 +            return 0x7f 
 +        if i&​lt;​-0x80:​ 
 +            return 0x80 
 +        if i&​lt;​0:​ 
 +            return 0x100+i 
 +        return i 
 + 
 +    @staticmethod 
 +    def _uint16(i):​ 
 +        i = round(i) 
 +        if i&​gt;​0xffff:​ 
 +            return 0xffff 
 +        if i&​lt;​0:​ 
 +            return 0 
 +        return i 
 + 
 +    def _status(self):​ 
 +        return self.bus.read_i2c_block_data(self.addr,​ 0, 1)[0] 
 + 
 +    def _wait_until_not_busy(self):​ 
 +        while self._status()==ERROR_BUSY:​ 
 +            time.sleep(0.001) 
 + 
 +    def hw_version(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns the major and minor versions of the PCB as a 2-item list. 
 +        &#​34;&#​34;&#​34;​  
 +        return self.bus.read_i2c_block_data(self.addr,​ 1, 2) 
 + 
 +    def fw_version(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns the major, minor and build versions of the firmware as  
 +        a 3-item list. 
 +        &#​34;&#​34;&#​34;​  
 +        return self.bus.read_i2c_block_data(self.addr,​ 3, 3) 
 + 
 +    def resource_url(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns the url of a JSON file that contains information about  
 +        resources, such as the location of the latest version of this code,  
 +        latest firmware, etc. 
 +        &#​34;&#​34;&#​34;​ 
 +        chars = self.bus.read_i2c_block_data(self.addr,​ 6, 32) 
 +        s = &#​39;&#​39;​ 
 +        for c in chars: 
 +            if c==0: # read up to the null character 
 +                break 
 +            s += chr(c) 
 +        return s 
 + 
 +    def uuid(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns a 16-byte unique ID that can be used an a unique 
 +        ID for your Vizy camera. ​ This unique ID is stored on the Vizy Power 
 +        Board and remains constant regardless of firmware upgrades, etc. 
 +        &#​34;&#​34;&#​34;​ 
 +        return self.bus.read_i2c_block_data(self.addr,​ 22, 16) 
 + 
 +    def power_off_requested(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns `True` if Vizy&#​39;​s ​button ​is held down for more than 5 seconds 
 +        indicating that the user wishes to initiate safe shutdown and power 
 +        off.  Returns `False` otherwise. 
 + 
 +        This is used by the vizy-powerd service.  
 +        &#​34;&#​34;&#​34;​ 
 +        button = self.bus.read_i2c_block_data(self.addr, 38, 1) 
 +        if button[0]==0x0f:​ 
 +            return True 
 +        else: 
 +            return False 
 + 
 +    def power_off(self,​ t=5000): 
 +        &#​34;&#​34;&#​34;​ 
 +        Powers Vizy off. The `t` argument specifies how long  
 +        to wait before turning off (specified in milliseconds). ​ The  
 +        vizy-powerd service calls this upon shutdown. 
 +        &#​34;&#​34;&#​34;​ 
 +        self.bus.write_i2c_block_data(self.addr,​ 38, [0x1f, int(t/​100)]) 
 + 
 +    def power_on_alarm_date(self,​ datetime_=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        If you wish to power off your Vizy and have it &#​34;​wake up&#34; at a 
 +        specified time and date, call this method with the desired 
 +        datetime object and initiate a shutdown. (e.g. `sudo shutdown now`). 
 + 
 + 
 +        The code below tells Vizy to turn on on December 2, 2022, 11:18am. 
 + 
 +            import vizypowerboard as vpb 
 +            from datetime import datetime 
 +            v = vpb.VizyPowerBoard() 
 +            d=datetime(year=2022,​ month=12, day=2, hour=11, minute=18, second=0) 
 +            v.power_on_alarm_date(d) 
 + 
 +        Args: 
 +          datetime_ (datetime, optional, default=None):​ `datetime` object that 
 +            specifies the date/time to &#​34;​wake up&#34; (turn on). 
 + 
 +        Returns: 
 +          Calling without a datetime object returns a `datetime` object  
 +          reflecting the active alarm time.  If there is no active alarm, 
 +          `None` is returned. 
 +            
 +        Notes: 
 +          * Once setting the alarm date, Vizy will retain it even if Vizy loses 
 +          power for extended periods of time. 
 +          * If the alarm expires while Vizy is on, Vizy will emit a buzzer tone 
 +          and remain on. 
 +          * If the alarm expires while Vizy is off (but plugged into and 
 +          receiving power), Vizy will turn on. 
 +          * If the alarm expires while Vizy is unplugged from (or not receiving) 
 +          power, Vizy will turn on as soon as it receives power. ​  
 +        &#​34;&#​34;&#​34;​ 
 +        if datetime_ is None: 
 +            t = self.bus.read_i2c_block_data(self.addr,​ 41, 6) 
 +            if t[5]==0: 
 +                return None 
 +            return datetime.datetime(year=self._bcd2decimal(t[5])+2016,​ month=self._bcd2decimal(t[4]),​ day=self._bcd2decimal(t[3]),​ hour=self._bcd2decimal(t[2]),​ minute=self._bcd2decimal(t[1]),​ second=self._bcd2decimal(t[0])) 
 +        t = [self._decimal2bcd(datetime_.second),​ self._decimal2bcd(datetime_.minute),​ self._decimal2bcd(datetime_.hour),​ self._decimal2bcd(datetime_.day),​ self._decimal2bcd(datetime_.month),​ self._decimal2bcd(datetime_.year-2016)] 
 +        self.bus.write_i2c_block_data(self.addr,​ 41, t) 
 +     
 + 
 +    def power_on_alarm_seconds(self,​ seconds=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Allows you to specify a power on alarm in seconds in the future.  
 +        For example, if you wish for Vizy to turn back on in 5 minutes, you 
 +        would call `power_on_alarm_seconds(300)` and then initiate a shutdown. 
 +        See `VizyPowerBoard.power_on_alarm_date()` for more information about the power on  
 +        alarm. 
 + 
 +        Args: 
 +          seconds (integer, optional, default=None):​ Number of seconds in the 
 +            future you wish Vizy to turn on in. 
 + 
 +        Returns: 
 +          Calling this method without arguments returns the number of seconds 
 +          until the alarm expires. ​ If no alarm is pending, `None` is returned. 
 +        &#​34;&#​34;&#​34;​ 
 +        if seconds is None: 
 +            pod = self.power_on_alarm_date() 
 +            if pod is None: 
 +                return None 
 +            diff = pod - self.rtc() 
 +            return diff.days*86400+diff.seconds  
 +        # Add seconds to current time and set power on alarm     
 +        self.power_on_alarm_date(self.rtc()+datetime.timedelta(seconds=seconds)) 
 + 
 +    def power_on_source(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns the source of what turned on Vizy for the current power cycle. 
 +        It is one of either: 
 + 
 +        * POWER_ON_SOURCE_ALARM,​ indicates that Vizy was powered on 
 +        by the power on alarm expiring. ​ See power_on_alarm_date() and 
 +        power_on_alarm_seconds(). 
 +        * POWER_ON_SOURCE_POWER_BUTTON,​ indicates that Vizy was powered  
 +        on by someone pressing the button. 
 +        * POWER_ON_SOURCE_12V = indicates that Vizy was powered on 
 +        by power being applied to 12V power input. ​ This only applies if the 
 +        dip switch power mode allows powering on by plugging in power via the 
 +        12V power input. 
 +        * POWER_ON_SOURCE_5V,​ indicates that Vizy was powered on by applying 
 +        power to the Raspberry Pi&#​39;​s USB-C power input. 
 +        &#​34;&#​34;&#​34;​ 
 +        source = self.bus.read_i2c_block_data(self.addr,​ 40, 1)[0] 
 +        return source 
 + 
 +    def button(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns `True` if the button is being pressed currently, `False` otherwise. 
 +        &#​34;&#​34;&#​34;​ 
 +        button = self.bus.read_i2c_block_data(self.addr,​ 47, 1) 
 +        if button[0]&​amp;​0x02:​ 
 +            return True 
 +        else: 
 +            return False 
 + 
 +    def button_pressed(self):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Returns `True` if the button was pressed within the last 5 seconds, 
 +        `False` otherwise. ​ This is useful if the polling is intermittant or 
 +        slow, as button presses are not missed (as long as you check at least 
 +        every 5 seconds!) 
 +        &#​34;&#​34;&#​34;​ 
 +        button = self.bus.read_i2c_block_data(self.addr,​ 47, 1) 
 +        if button[0]&​amp;​0x01:​ 
 +            # Reset bit 
 +            self.bus.write_i2c_block_data(self.addr,​ 47, [0]) 
 +            return True 
 +        else: 
 +            return False 
 + 
 +    def vcc12(self, state=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        If `state` is `True`, the 12V output on Vizy&#​39;​s I/O connector (pin 2) will be enabled and output 12V.  If `state` is `False`, the 12V output 
 +        will be disabled. ​ Calling without arguments returns its current state. 
 +        &#​34;&#​34;&#​34;​  
 +        config = self.bus.read_i2c_block_data(self.addr,​ 48, 1) 
 +        if state is None: 
 +            return True if config&​amp;​0x01 else False 
 +        if state: 
 +            config[0] |= 0x01 
 +        else: 
 +            config[0] &amp;= ~0x01 
 + 
 +        self.bus.write_i2c_block_data(self.addr,​ 48, config) 
 + 
 +    def vcc5(self, state=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        If `state` is `True`, the 5V output on Vizy&#​39;​s I/O connector (pin 3) will 
 +        be enabled and output 5V.  If `state` is `False`, the 5V output will be 
 +        disabled. ​ Calling without arguments returns its current state. 
 +        &#​34;&#​34;&#​34;​  
 +        if state is None: 
 +            return True if config&​amp;​0x02 else False 
 +        if state: 
 +            config[0] |= 0x02 
 +        else: 
 +            config[0] &amp;= ~0x02 
 + 
 +        self.bus.write_i2c_block_data(self.addr,​ 48, config) 
 + 
 +    def led(self, r=0, g=0, b=0, flashes=0, repeat=False,​ atten=255, on=100, off=100, pause=200):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Controls the RGB LED in one of several modes: 
 + 
 +        * **Continuous**:​ just setting `r`, `g`, and `b` will set set the LED color 
 +        and turn it on continuously. ​ `r`, `g`, and `b` values range between 0  
 +        and  255. 
 + 
 +                led(255, 0, 0)   # turn on LED, red color 
 +                led(255, 255, 0) # turn on LED, yellow color 
 +                led(0, 0, 255)   # turn on LED, blue color 
 +                led(0, 0, 0)     # turn off LED 
 + 
 +        * **Flashes**:​ setting the `flashes` value to a non-zero value will 
 +        cause the LED to flash the indicated number of times. ​ You can also 
 +        specify the `on` and `off` arguments to indicate the amount of time  
 +        the LED is on and off for each flash (specified in milliseconds). 
 + 
 +                led(0, 0, 255, 3)  # flash blue 3 times (then stop) 
 +                led(0, 0, 255, 3, on=500, off=500) ​ # flash blue 3 times, much more slowly 
 + 
 +        * **Repeated flashes**: setting the `repeat` argument to `True`  
 +        will cause the indicated flash pattern to repeat forever. ​ You can 
 +        modify the pause time between flash sequences by setting `pause` 
 +        (milliseconds). 
 + 
 +                led(0, 0, 255, 3, True, pause=500) ​ # flash blue 3 times, pause, then repeat 
 +                led(0, 0, 255, repeat=True,​ on=500, off=500)` ​ # flash blue forever 
 + 
 +        * **Flashing with attenuation**:​ you can also set the `atten`  
 +        argument to make the LED to turn on and off slowly, like an 
 +        incandescent light. ​ The value is the rate of change, so lower values 
 +        cause the LED color to change more slowly.  
 + 
 +                led(0, 0, 255, repeat=True,​ atten=10, on=500, off=500) # flash blue forever, but turn on and turn off very slowly 
 +        &#​34;&#​34;&#​34;​ 
 +        on = self._u_int8(on/​10) 
 +        off = self._u_int8(off/​10) 
 +        pause = self._u_int8(pause/​10) 
 +        if flashes==0:​ 
 +            mode = 0 
 +        if repeat: 
 +            mode = 0x02 
 +        else: 
 +            mode = 0x01 
 +        self.bus.write_i2c_block_data(self.addr,​ 49, [mode, self._u_int8(r),​ self._u_int8(g),​ self._u_int8(b),​ 
 +            on, off, self._u_int8(flashes),​ pause, self._u_int8(atten)]) 
 + 
 +    def led_unicorn(self,​ speed=10):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        This causes the LED to change color in succession: red, orange, yellow,  
 +        green, cyan, blue, violet and then repeat again. ​ The `speed` argument  
 +        ranges between 0 and 10.  For example, a `speed` of 0 causes the color  
 +        to change once every couple of seconds. ​ A `speed` of 10 causes the color to change about 6 times per second. 
 +        &#​34;&#​34;&#​34;​ 
 +        if speed&​gt;​10:​ 
 +            speed = 10 
 +        elif speed&​lt;​0:​ 
 +            speed = 0 
 + 
 +        on = self._u_int8(10 + (10-speed)*140/​10) 
 +        atten = self._u_int8(3 + speed*47/​10) ​    
 +        self.bus.write_i2c_block_data(self.addr,​ 49, [0x08, 0, 0, 0, on, 0, 0, 0, atten]) 
 + 
 +    def led_background(self,​ r=-1, g=-1, b=-1): 
 +        &#​34;&#​34;&#​34;​ 
 +        The &#​34;​background&#​34;​ LED color is the color of the LED when the LED is  
 +        turned &#​34;​off&#​34;​. ​ It is used by system programs such as vizy-powerd to 
 +        indicate Vizy&#​39;​s system state such as, booting (yellow), finished 
 +        booting (green), running server (blue), etc.  Note, the background 
 +        color does not influence the LED colors set by calls to led(). 
 + 
 +        Calling led_background() without arguments returns the current  
 +        background color r, g, and b values in a list.  
 + 
 +            led_background(48,​ 48, 0)  # set background color to yellow 
 +            led(0, 255, 0)  # turn on LED, green (as expected) 
 +            led(0, 0, 0)  # turn LED off, and restore background color (yellow as set previously) ​    
 +        &#​34;&#​34;&#​34;​ 
 +        if r==-1: 
 +            return self.bus.read_i2c_block_data(self.addr,​ 58, 3) 
 +        self.bus.write_i2c_block_data(self.addr,​ 58, [self._u_int8(r),​ self._u_int8(g),​ self._u_int8(b)]) 
 +  
 + 
 +    def buzzer(self,​ freq, on=250, off=250, count=1, shift=0): 
 +        &#​34;&#​34;&#​34;​ 
 +        Emit tones through the buzzer. ​ The `freq` argument sets the frequency  
 +        of the tone in Hz and the `on` argument sets the length of the tone in 
 +        milliseconds. ​  
 + 
 +        If you wish to emit more than 1 tone, you can set the 
 +        `count` argument to the desired number. ​  
 + 
 +        The `off` argument sets  
 +        the pause between tones in milliseconds. ​ The `shift` argument is a 
 +        value ranging between -128 and 127 that causes the tone&#​39;​s frequency to 
 +        raise if `shift` is greater than 0, or descend if `shift` is less  
 +        than 0. 
 + 
 +            buzzer(2000,​ 500) # emit a 2000Hz tone for 500ms 
 +            buzzer(1000,​ count=3) # emit a 1000Hz tone 3 times    
 +            buzzer(1000,​ 500, 100, 3) # emit a longer 1000Hz tone 3 times 
 +            buzzer(500, 250, 0, 10, 50) # emit 10 warbling tones like a siren 
 +        &#​34;&#​34;&#​34;​ 
 +        freq = self._uint16(freq) 
 +        f0 = freq&​amp;​0xff 
 +        f1 = (freq&​gt;&​gt;​8)&​amp;​0xff 
 +        self.bus.write_i2c_block_data(self.addr,​ 61, [0, f0, f1, self._u_int8(on/​10),​ self._u_int8(off/​10),​  
 +            self._u_int8(count),​ self._int8(shift)]) 
 + 
 + 
 +    def io_set_mode(self,​ bit, mode=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Sets or gets the io mode of the given bit.  The `bit` argument ranges 
 +        between ​ 0 and 3 and corresponds to pins 4 through 7 on Vizy&#​39;​s IO 
 +        connector. Calling this method with no mode argument returns the mode 
 +        of the given bit, otherwise, the `mode` argument can be one of  
 +        the following:​ 
 + 
 +        * IO_MODE_INPUT,​ sets the bit to high impedance input mode with  
 +        a weak pull-up resistor to 3.3V.  The input voltage can range between 
 +        0 and Vin where Vin is the supply voltage. ​ Voltages lower than 1V  
 +        read as logic 0 via `VizyPowerBoard.io_bits()`. ​ Voltages higher  
 +        than 1V are read as logic 1. 
 +        * IO_MODE_OUTPUT,​ sets the bit to output mode.  If the bit is set to 
 +        logic 0 via `VizyPowerBoard.io_bits()`,​ the output voltage is 0V.   
 +        If the bit is set to logic 1, the output voltage is 3.3V.  In this mode, each bit can source and sink 5mA.   
 +        * IO_MODE_HIGH_CURRENT,​ sets the bit to a special high current mode 
 +        that allows the bit to sink as much as 1000mA, when the bit  
 +        set to logic 0 via `VizyPowerBoard.io_bits()`. ​ Otherwise, this mode 
 +        behaves exactly as IO_MODE_OUTPUT. ​    
 +        &#​34;&#​34;&#​34;​ 
 +        if mode is None: 
 +            return self.bus.read_i2c_block_data(self.addr,​ 68+bit, 1)[0] 
 +        if bit==2: 
 +            # set GPIO14 (UART TXD) as input so it doesn&#​39;​t conflict 
 +            GPIO.setwarnings(False) 
 +            GPIO.setmode(GPIO.BOARD) 
 +            GPIO.setup(8,​ GPIO.IN) 
 +        self.bus.write_i2c_block_data(self.addr,​ 68+bit, [self._u_int8(mode)]) 
 + 
 +    def io_bits(self,​ bits=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Sets or gets the logic state of the IO bits 0 through 3, corresponding 
 +        to pins 4 through 7 on Vizy&#​39;​s IO connector. ​ The `bits` argument ranges 
 +        between 0 and 15 as it is a binary representation of the logic state 
 +        of the 4 IO bits.  If the `bits` argument isn&#​39;​t specified, the logic 
 +        state of the 4 bits are returned. 
 + 
 +            io_bits(1) ​  # set IO bit 0 to logic 1 and bits 1, 2, 3 to logic 0 
 +            io_bits(10) ​ # set IO bits 1 and 3 to logic 1 and bits 0 and 2 to logic 0 
 +            bits = io_bits() ​ # get logic state of IO bits 
 +            io_bits(io_bits()|1) ​ # set IO bit 0 to logic 1, leave bits 1, 2, 3 unchanged.  
 +        &#​34;&#​34;&#​34;​ 
 +        if bits is None: 
 +            return self.bus.read_i2c_block_data(self.addr,​ 72, 1) 
 +        self.bus.write_i2c_block_data(self.addr,​ 72, [bits]) 
 + 
 + 
 +    def ir_filter(self,​ state=None, duration=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Actuates the electro-mechanical IR-cut filter on Vizy&#​39;​s camera. ​ Vizy 
 +        uses a CMOS sensor which is very sensitive to IR light. ​ IR light can  
 +        adversely affect color fidelity during the daytime so an IR-cut filter 
 +        is used to block the IR light (`state`=True). ​ During nighttime IR light 
 +        is typically used as a discreet method of illumination and the IR-cut 
 +        filter is removed (`state`=False). ​ If the `state` argument is `True`, 
 +        the filter is actuated in place (and will stay there) until another 
 +        call is made with the state argument set to `False` (in which case the 
 +        IR-cut filter will be removed). ​  
 + 
 +        The `duration` argument is optional and 
 +        controls how long (in milliseconds) the actuation coil receives power. 
 + 
 +        Calling this method without arguments returns the state of IR-cut 
 +        filter. 
 +        &#​34;&#​34;&#​34;​ 
 +        if state is None: 
 +            return True if self.bus.read_i2c_block_data(self.addr,​ 73, 1)[0] else False 
 +        data = [1] if state else [0] 
 +        if duration is not None: 
 +            data.append(int(duration/​10)) 
 +        self.bus.write_i2c_block_data(self.addr,​ 73, data) 
 + 
 +    def fan(self, speed=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Set or get the fan speed. ​ The `speed` argument can range between 0  
 +        and 12 where 0 is off and 12 is maximum speed. ​ The fan speed  
 +        is typically regulated automatically by vizy-powerd. 
 + 
 +        Calling this method without arguments returns the current fan speed. ​  
 +        &#​34;&#​34;&#​34;​ 
 +        if speed is None: 
 +            return self.bus.read_i2c_block_data(self.addr,​ 75, 1)[0] 
 +        self.bus.write_i2c_block_data(self.addr,​ 75, [self._u_int8(speed)]) 
 +        
 + 
 +    def rtc(self, datetime_=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Set or get the real-time clock time/​date. ​ The Vizy power board has a  
 +        battery-backed real-time clock that keeps track of time/date, power  
 +        alarms, etc. even while Vizy is receiving no power. ​ Passing in a 
 +        datetime object sets the time/​date. ​  
 + 
 +        Calling this method with no 
 +        arguments returns a datetime object representing the current  
 +        date/time.  
 + 
 +        For example, the code below sets the date to December 2, 2020, 11:18am: 
 + 
 +            from datetime import datetime 
 +            import vizypowerboard as vpb 
 +            v = vpb.VizyPowerBoard() 
 +            t = datetime(year=2020,​ month=12, day=2, hour=11, minute=18, second=0) 
 +            v.rtc(t) 
 +        &#​34;&#​34;&#​34;​ 
 +        if datetime_ is None: 
 +            # Initiate RTC retrieval. 
 +            self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC]) 
 +            # Wait until it&#​39;​s ready. 
 +            self._wait_until_not_busy() 
 + 
 +            t = self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 8) 
 +            return datetime.datetime(year=self._bcd2decimal(t[7])+2016,​ month=self._bcd2decimal(t[6]),​ day=self._bcd2decimal(t[4]),​ hour=self._bcd2decimal(t[3]),​ minute=self._bcd2decimal(t[2]),​ second=self._bcd2decimal(t[1])) 
 +  
 +        t = [EXEC_RTC|EXEC_WRITE,​ 0, self._decimal2bcd(datetime_.second),​ self._decimal2bcd(datetime_.minute),​ self._decimal2bcd(datetime_.hour),​ self._decimal2bcd(datetime_.day),​ 0, self._decimal2bcd(datetime_.month),​ self._decimal2bcd(datetime_.year-2016)] 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ t) 
 +        self._wait_until_not_busy() 
 + 
 +    def dip_switches(self,​ val=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Set or get the (virtual) DIP switch state. ​ The DIP switches are a set  
 +        of &#​34;​switches&#​34;​ that allow you to control Vizy&#​39;​s power-on or power-off 
 +        behavior. ​ Once they are set, they will retain the setting even if  
 +        power is removed.  
 +        The switches are a set of values that can be ORed together: 
 + 
 +        * DIPSWITCH_EXT_BUTTON,​ used to set external/​remote power button,  
 +        e.g. with outdoor enclosure. ​ Default disabled. 
 +        * DIPSWITCH_MUTE_BUZZER,​ used to mute the buzzer. ​ Default disabled. 
 +        * DIPSWITCH_NO_BG_LED,​ used to disable the background LED, which is  
 +        normally set to yellow upon power up.  Default disabled. 
 +        * DIPSWITCH_POWER_DEFAULT_OFF,​ if this power mode is set and you  
 +        plug in power via the 12V power input, Vizy will remain off by default 
 +        until you press the button to power Vizy on.  And if power is 
 +        interrupted while Vizy is on, *Vizy will turn off*.  If power is 
 +        interrupted while Vizy is off, Vizy will remain off.  This is the 
 +        default power mode. 
 +        * DIPSWITCH_POWER_DEFAULT_ON,​ if this power mode is set and you  
 +        plug in power via the 12V power input, Vizy will turn on by default 
 +        without pressing the button. ​ And if power is interrupted while Vizy 
 +        is on, Vizy will reset, but remain on.  If power is interrupted while 
 +        Vizy is off, *Vizy will turn on*.  Default disabled. 
 +        * DIPSWITCH_POWER_SWITCH,​ if this power mode is set and you plug in 
 +        power via the 12V power input, Vizy will remain off (as in 
 +        DIPSWITCH_POWER_DEFAULT_OFF mode), unless power was  
 +        removed while Vizy was on.  In this case Vizy will turn on when you 
 +        (re)apply power. ​ If power is interrupted while Vizy is off, Vizy  
 +        will remain off.  This behavior is similar to the behavior of a real 
 +        power switch in that it retains the power &#​34;​state&#​34;​ (on or off) and acts 
 +        accordingly. ​ Default disabled. 
 +        * DIPSWITCH_POWER_PLUG,​ if this power mode is set Vizy will remain 
 +        powered on as long as it receives power through the 12V power plug,  
 +        and you will not be able to turn off Vizy via button or software as 
 +        long as it&#​39;​s plugged in and receiving power. ​ Default disabled. 
 +         
 +        For example:  
 + 
 +            dip_switches(DIPSWITCH_EXT_BUTTON | DIPSWITCH_POWER_SWITCH) # set external power button and power switch mode 
 +        &#​34;&#​34;&#​34;​ 
 +        if val is None: 
 +            self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_NVCONFIG]) 
 +            # Wait until it&#​39;​s ready. 
 +            self._wait_until_not_busy() 
 +            return self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 1)[0] 
 + 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_NVCONFIG|EXEC_WRITE,​ self._u_int8(val)]) 
 +        self._wait_until_not_busy() 
 + 
 +    def rtc_adjust(self,​ val=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        Set or get the real-time clock adjustment. ​ Vizy&#​39;​s real-time clock  
 +        crystal has an accuracy of 20ppm, which means that it can lose or gain  
 +        up to 20 seconds for every 1 million elapsed seconds. ​ Normally, this 
 +        isn&#​39;​t an issue, but if Vizy spends a lengthy period of time (months) 
 +        without Internet access, it could lose or gain minutes, which  
 +        depending on the application could be significant. The adjustment 
 +        value can offset this inaccuracy. ​ The `val` argument can range  
 +        between -128 and 127 and has a multiplier of 2.170 ppm.   
 + 
 +        For example,  
 +        if the RTC is gaining 10 seconds every 1 million seconds, you would  
 +        call `rtc_adjust(-5)`. ​ If the RTC is losing 10 seconds every million 
 +        seconds you would call `rtc_adjust(5)`. 
 +         
 +        The adjustment value is retained by the real-time clock even when  
 +        Vizy&#​39;​s power is removed.  
 +        &#​34;&#​34;&#​34;​ 
 +        if val is None: 
 +            self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC_CALIBRATE]) 
 +            # Wait until it&#​39;​s ready. 
 +            self._wait_until_not_busy() 
 +            return self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 1)[0] 
 + 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC_CALIBRATE|EXEC_WRITE,​ self._int8(val)]) 
 +        self._wait_until_not_busy() 
 + 
 + 
 +    def measure(self,​ channel): 
 +        &#​34;&#​34;&#​34;​ 
 +        Get the voltage values of various channels. ​ The returned value is  
 +        the voltage measured (in Volts) of the given channel. ​ The `channel` 
 +        argument can be one of the following:​ 
 + 
 +        * CHANNEL_VIN,​ this channel measures the voltage present at the 12V 
 +        power input. 
 +        * CHANNEL_5V, this channel measures the voltage present at the 5V 
 +        voltage rail provided to the Raspberry Pi. 
 +        &#​34;&#​34;&#​34; ​  
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_AD, self._u_int8(channel)]) 
 +        # Wait until it&#​39;​s ready. 
 +        self._wait_until_not_busy() 
 +        val = self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+2,​ 2) 
 +        return (val[1]*0x100 + val[0])/​1000 
 + 
 + 
 +    def rtc_set_system_datetime(self,​ datetime_=None):​ 
 +        &#​34;&#​34;&#​34;​ 
 +        A convenience method that sets the system time/date based on the  
 +        real-time time/​date. ​ This is called by vizy-powerd upon power-up.  
 +        &#​34;&#​34;&#​34;​ 
 +        if os.geteuid()!=0:​ 
 +            raise PermissionError(&#​34;​You need root permission to set the time/​date.&#​34;​) 
 +        if datetime_ is None: 
 +            datetime_ = self.rtc() 
 +        s = datetime_.isoformat() 
 +        os.system(f&#​34;​sudo date -s {s}&#​34;​)</code></pre> 
 +</​details>​ 
 +<​h3>​Methods</​h3>​ 
 +<​dl>​ 
 +<dt id="​vizypowerboard.VizyPowerBoard.button"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident">​button</span></​span>​(<​span>​self)</​span
 +</code></​dt>​ 
 +<dd> 
 +<div class="​desc"><​p>​Returns <​code>​True</codeif the button is being pressed currently, <​code>​False</​code>​ otherwise.</​p></​div>​ 
 +<details class="​source">​ 
 +<​summary>​ 
 +<​span>​Expand source code</​span>​ 
 +</​summary>​ 
 +<​pre><​code class="​python">​def button(self):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    ​Returns ​`Trueif the button is being pressed currently, ​`Falseotherwise. 
 +    &#​34;&#​34;&#​34;​ 
 +    button = self.bus.read_i2c_block_data(self.addr,​ 47, 1) 
 +    if button[0]&​amp;​0x02:​ 
 +        return True 
 +    else: 
 +        return False</code></pre> 
 +</details
 +</dd> 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.button_pressed"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>​button_pressed</​span></​span>​(<​span>​self)</span> 
 +</code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Returns <​code>​True</codeif the button was pressed within the last 5 seconds, 
 +<code>False</codeotherwise. 
 +This is useful if the polling is intermittant or 
 +slow, as button presses are not missed (as long as you check at least 
 +every 5 seconds!)</p></​div>​ 
 +<details class="​source">​ 
 +<​summary>​ 
 +<​span>​Expand source code</​span>​ 
 +</​summary>​ 
 +<​pre><​code class="​python">​def button_pressed(self):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    ​Returns ​`Trueif the button was pressed within the last 5 seconds, 
 +    `Falseotherwise. ​ This is useful if the polling is intermittant or 
 +    ​slow, as button presses are not missed (as long as you check at least 
 +    ​every 5 seconds!) 
 +    &#​34;&#​34;&#​34;​ 
 +    button = self.bus.read_i2c_block_data(self.addr,​ 47, 1) 
 +    if button[0]&​amp;​0x01:​ 
 +        # Reset bit 
 +        self.bus.write_i2c_block_data(self.addr,​ 47, [0]) 
 +        return True 
 +    else: 
 +        return False</code></pre> 
 +</details
 +</dd> 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.buzzer"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>buzzer</​span></​span>​(<​span>​self, freq, on=250, off=250, count=1, shift=0)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​Emit tones through the buzzer. 
 +The <​code>​freq</​code> ​argument sets the frequency 
 +of the tone in Hz and the <​code>​on</​code> ​argument sets the length of the tone in 
 +milliseconds. 
 +</​p>​ 
 +<p>If you wish to emit more than 1 tone, you can set the 
 +<​code>​count</​code> ​argument to the desired number. 
 +</​p>​ 
 +<p>The <code>off</code> argument sets 
 +the pause between tones in milliseconds. 
 +The <​code>​shift</​code> ​argument is a 
 +value ranging between -128 and 127 that causes the tone's frequency to 
 +raise if <​code>​shift</​code> ​is greater than 0, or descend if <​code>​shift</​code> ​is less 
 +than 0.</​p>​ 
 +<pre><​code>​buzzer(2000,​ 500) # emit a 2000Hz tone for 500ms
 buzzer(1000,​ count=3) # emit a 1000Hz tone 3 times    buzzer(1000,​ count=3) # emit a 1000Hz tone 3 times   
 buzzer(1000,​ 500, 100, 3) # emit a longer 1000Hz tone 3 times buzzer(1000,​ 500, 100, 3) # emit a longer 1000Hz tone 3 times
 buzzer(500, 250, 0, 10, 50) # emit 10 warbling tones like a siren buzzer(500, 250, 0, 10, 50) # emit 10 warbling tones like a siren
-</code><​HTML></dd></HTML+</​code></​pre></div
-<HTML><​dt></​HTML>''​%%dip_switches(self,​ val=None)%%''<​HTML></​dt></​HTML+<details class="​source"​
-<HTML><​dd></​HTML><​HTML><​p></​HTML>​Set or get the (virtual) DIP switch state. The DIP switches are a set of “switches” that allow you to control Vizy’s power-on or power-off behavior. Once they are set, they will retain the setting even if power is removed. The switches are a set of values that can be ORed together:<​HTML></​p></​HTML+<summary
-<HTML><​ul></HTML+<span>Expand source code</span
-<​HTML><​li></​HTML>​DIPSWITCH_EXT_BUTTON,​ used to set external/​remote power button, e.g. with outdoor enclosure. Default disabled.<​HTML></​li>​</HTML+</summary
-<HTML><li></​HTML>​DIPSWITCH_MUTE_BUZZER,​ used to mute the buzzer. Default disabled.<​HTML></​li></​HTML>​ +<pre><code class="​python"​>def buzzer(selffreqon=250, off=250count=1shift=0): 
-<​HTML><​li></​HTML>​DIPSWITCH_NO_BG_LEDused to disable the background LEDwhich is normally set to yellow upon power up. Default disabled.<​HTML></​li></​HTML>​ +    &#​34;&#​34;&#​34;​ 
-<​HTML><​li></​HTML>​DIPSWITCH_POWER_DEFAULT_OFFif this power mode is set and you plug in power via the 12V power input, Vizy will remain ​off by default until you press the button to power Vizy on. And if power is interrupted while Vizy is on//Vizy will turn off//. If power is interrupted while Vizy is offVizy will remain offThis is the default power mode.<​HTML></​li></​HTML>​ +    Emit tones through the buzzer The `freq` argument sets the frequency ​ 
-<​HTML><​li></​HTML>​DIPSWITCH_POWER_DEFAULT_ON,​ if this power mode is set and you plug in power via the 12V power input, Vizy will turn on by default without pressing the button. And if power is interrupted while Vizy is on, Vizy will reset, but remain on. If power is interrupted while Vizy is off, //Vizy will turn on//. Default disabled.<​HTML></​li></​HTML>​ +    of the tone in Hz and the `on` argument sets the length ​of the tone in 
-<​HTML><​li></​HTML>​DIPSWITCH_POWER_SWITCH,​ if this power mode is set and you plug in power via the 12V power input, Vizy will remain off (as in DIPSWITCH_POWER_DEFAULT_OFF mode), unless power was removed while Vizy was on. In this case Vizy will turn on when you (re)apply power. If power is interrupted while Vizy is off, Vizy will remain off. This behavior is similar to the behavior ​of a real power switch ​in that it retains the power “state” (on or off) and acts accordingly. Default disabled.<​HTML></​li></​HTML>​ +    ​milliseconds 
-<​HTML><​li></​HTML>​DIPSWITCH_POWER_PLUG,​ if this power mode is set Vizy will remain powered on as long as it receives power through the 12V power plug, and you will not be able to turn off Vizy via button or software as long as it’s plugged in and receiving powerDefault disabled.<​HTML></​li></​HTML><​HTML></​ul></​HTML>​+
  
-<HTML><p></HTML>For example:<HTML></​p></​HTML+    If you wish to emit more than 1 tone, you can set the 
-<​code>​ +    `count` argument to the desired number. ​  
-dip_switches(DIPSWITCH_EXT_BUTTON | DIPSWITCH_POWER_SWITCH) # set external power button and power switch mode + 
-</​code><​HTML></dd></HTML+    The `off` argument sets  
-<HTML><dt></HTML>''​%%fan(self, ​speed=None)%%''​<HTML></dt></HTML+    the pause between tones in milliseconds. ​ The `shift` argument is a 
-<HTML><dd></HTML><HTML><p></HTML>Set or get the fan speed. The ''​%%speed%%'' ​argument can range between 0 and 12 where 0 is off and 12 is maximum speed. The fan speed is typically regulated automatically by vizy-powerd.<​HTML></​p></​HTML+    value ranging between -128 and 127 that causes the tone&#​39;​s frequency to 
-<HTML><p></HTML>Calling this method without arguments returns the current fan speed.<HTML></p></HTML><​HTML></​dd><​/HTML+    raise if `shift` is greater than 0, or descend if `shift` is less  
-<HTML><dt></HTML>''​%%fw_version(self)%%''​<HTML></​dt></​HTML+    than 0. 
-<HTML><dd></HTML>Returns the major, minor and build versions of the firmware as a 3-item list.<HTML></dd></HTML+ 
-<HTML><​dt><​/HTML>''​%%hw_version(self)%%''​<HTML></​dt></​HTML+        buzzer(2000,​ 500) # emit a 2000Hz tone for 500ms 
-<HTML><dd></HTML>Returns the major and minor versions of the PCB as a 2-item list.<HTML></dd></HTML+        buzzer(1000,​ count=3) # emit a 1000Hz tone 3 times    
-<HTML><​dt><​/HTML>''​%%io_bits(self,​ bits=None)%%''​<HTML></dt></HTML+        buzzer(1000,​ 500, 100, 3) # emit a longer 1000Hz tone 3 times 
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>Sets or gets the logic state of the IO bits 0 through 3, corresponding to pins 4 through 7 on Vizys IO connector. The ''​%%bits%%'' ​argument ranges between 0 and 15 as it is a binary representation of the logic state of the 4 IO bits. If the ''​%%bits%%'' ​argument isnt specified, the logic state of the 4 bits are returned.<​HTML>​</​p><​/HTML> +        buzzer(500, 250, 0, 10, 50) # emit 10 warbling tones like a siren 
-<​code>​ +    &#​34;&#​34;&#​34;​ 
-io_bits(1) ​  # set IO bit 0 to logic 1 and bits 1, 2, 3 to logic 0+    freq = self._uint16(freq) 
 +    f0 = freq&​amp;​0xff 
 +    f1 = (freq&​gt;&​gt;​8)&​amp;​0xff 
 +    self.bus.write_i2c_block_data(self.addr,​ 61, [0, f0, f1, self._u_int8(on/​10),​ self._u_int8(off/​10),​  
 +        self._u_int8(count),​ self._int8(shift)])</code></pre> 
 +</details> 
 +</​dd>​ 
 +<dt id="​vizypowerboard.VizyPowerBoard.dip_switches"><​code class="​name flex">​ 
 +<​span>​def <span class="​ident">​dip_switches</​span></​span>​(<​span>​self,​ val=None)</​span>​ 
 +</​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Set or get the (virtual) DIP switch state. 
 +The DIP switches are a set 
 +of "​switches"​ that allow you to control Vizy's power-on or power-off 
 +behavior. 
 +Once they are set, they will retain the setting even if 
 +power is removed. 
 +The switches are a set of values that can be ORed together:</p> 
 +<ul> 
 +<​li>​DIPSWITCH_EXT_BUTTON,​ used to set external/remote power button, 
 +e.g. with outdoor enclosure. 
 +Default disabled.</​li>​ 
 +<​li>​DIPSWITCH_MUTE_BUZZER,​ used to mute the buzzer. 
 +Default disabled.</​li>​ 
 +<​li>​DIPSWITCH_NO_BG_LED,​ used to disable the background LED, which is 
 +normally set to yellow upon power up. 
 +Default disabled.</​li>​ 
 +<​li>​DIPSWITCH_POWER_DEFAULT_OFF,​ if this power mode is set and you 
 +plug in power via the 12V power input, Vizy will remain off by default 
 +until you press the button to power Vizy on. 
 +And if power is 
 +interrupted while Vizy is on, <​em>​Vizy will turn off</​em>​. 
 +If power is 
 +interrupted while Vizy is off, Vizy will remain off. 
 +This is the 
 +default power mode.</​li>​ 
 +<​li>​DIPSWITCH_POWER_DEFAULT_ON,​ if this power mode is set and you 
 +plug in power via the 12V power input, Vizy will turn on by default 
 +without pressing the button. 
 +And if power is interrupted while Vizy 
 +is on, Vizy will reset, but remain on. 
 +If power is interrupted while 
 +Vizy is off, <​em>​Vizy will turn on</​em>​. 
 +Default disabled.</​li>​ 
 +<​li>​DIPSWITCH_POWER_SWITCH,​ if this power mode is set and you plug in 
 +power via the 12V power input, Vizy will remain off (as in 
 +DIPSWITCH_POWER_DEFAULT_OFF mode), unless power was 
 +removed while Vizy was on. 
 +In this case Vizy will turn on when you 
 +(re)apply power. 
 +If power is interrupted while Vizy is off, Vizy 
 +will remain off. 
 +This behavior is similar to the behavior of a real 
 +power switch in that it retains the power "​state"​ (on or off) and acts 
 +accordingly. 
 +Default disabled.</​li>​ 
 +<​li>​DIPSWITCH_POWER_PLUG,​ if this power mode is set Vizy will remain 
 +powered on as long as it receives power through the 12V power plug, 
 +and you will not be able to turn off Vizy via button or software as 
 +long as it's plugged in and receiving power. 
 +Default disabled.</​li>​ 
 +</​ul>​ 
 +<p>For example: ​</p
 +<pre><​code>​dip_switches(DIPSWITCH_EXT_BUTTON | DIPSWITCH_POWER_SWITCH) # set external power button and power switch mode 
 +</​code><​/pre></div> 
 +<details class="​source"​
 +<summary> 
 +<span>Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def dip_switches(self, ​val=None)
 +    &#​34;&#​34;&#​34;​ 
 +    Set or get the (virtual) DIP switch state. ​ The DIP switches are a set  
 +    of &#​34;​switches&#​34;​ that allow you to control Vizy&#​39;​s power-on or power-off 
 +    behavior. ​ Once they are set, they will retain the setting even if  
 +    power is removed.  
 +    The switches are a set of values that can be ORed together: 
 + 
 +    * DIPSWITCH_EXT_BUTTON,​ used to set external/​remote power button,  
 +    e.g. with outdoor enclosure. ​ Default disabled. 
 +    * DIPSWITCH_MUTE_BUZZER,​ used to mute the buzzer. ​ Default disabled. 
 +    * DIPSWITCH_NO_BG_LED,​ used to disable the background LED, which is  
 +    normally set to yellow upon power up.  Default disabled. 
 +    * DIPSWITCH_POWER_DEFAULT_OFF,​ if this power mode is set and you  
 +    plug in power via the 12V power input, Vizy will remain off by default 
 +    until you press the button to power Vizy on.  And if power is 
 +    interrupted while Vizy is on, *Vizy will turn off*.  If power is 
 +    interrupted while Vizy is off, Vizy will remain off.  This is the 
 +    default power mode. 
 +    * DIPSWITCH_POWER_DEFAULT_ON,​ if this power mode is set and you  
 +    plug in power via the 12V power input, Vizy will turn on by default 
 +    without pressing the button. ​ And if power is interrupted while Vizy 
 +    is on, Vizy will reset, but remain on.  If power is interrupted while 
 +    Vizy is off, *Vizy will turn on*.  Default disabled. 
 +    * DIPSWITCH_POWER_SWITCH,​ if this power mode is set and you plug in 
 +    power via the 12V power input, Vizy will remain off (as in 
 +    DIPSWITCH_POWER_DEFAULT_OFF mode), unless power was  
 +    removed while Vizy was on.  In this case Vizy will turn on when you 
 +    (re)apply power. ​ If power is interrupted while Vizy is off, Vizy  
 +    will remain off.  This behavior is similar to the behavior of a real 
 +    power switch in that it retains the power &#​34;​state&#​34;​ (on or off) and acts 
 +    accordingly. ​ Default disabled. 
 +    * DIPSWITCH_POWER_PLUG,​ if this power mode is set Vizy will remain 
 +    powered on as long as it receives power through the 12V power plug,  
 +    and you will not be able to turn off Vizy via button or software as 
 +    long as it&#​39;​s plugged in and receiving power. ​ Default disabled. 
 +     
 +    For example:  
 + 
 +        dip_switches(DIPSWITCH_EXT_BUTTON | DIPSWITCH_POWER_SWITCH) # set external power button and power switch mode 
 +    &#​34;&#​34;&#​34;​ 
 +    if val is None: 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_NVCONFIG]) 
 +        # Wait until it&#​39;​s ready. 
 +        self._wait_until_not_busy() 
 +        return self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 1)[0] 
 + 
 +    self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_NVCONFIG|EXEC_WRITE,​ self._u_int8(val)]) 
 +    self._wait_until_not_busy()</code></pre> 
 +</details
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.fan"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident">​fan</span></span>(<span>self, speed=None)</span> 
 +</​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>Set or get the fan speed. 
 +The <​code>​speed</​code> ​argument can range between 0 
 +and 12 where 0 is off and 12 is maximum speed. 
 +The fan speed 
 +is typically regulated automatically by vizy-powerd.<​/p> 
 +<​p>​Calling this method without arguments returns the current fan speed.</​p></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def fan(self, speed=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    Set or get the fan speed. ​ The `speed` argument can range between 0  
 +    and 12 where 0 is off and 12 is maximum speed. ​ The fan speed  
 +    is typically regulated automatically by vizy-powerd. 
 + 
 +    ​Calling this method without arguments returns the current fan speed. ​  
 +    &#​34;&#​34;&#​34;​ 
 +    if speed is None: 
 +        return self.bus.read_i2c_block_data(self.addr,​ 75, 1)[0] 
 +    self.bus.write_i2c_block_data(self.addr,​ 75, [self._u_int8(speed)])</code></pre> 
 +</details> 
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.fw_version"><​code class="​name flex"
 +<span>def <span class="​ident"​>fw_version</span></​span>(<​span>​self)</span> 
 +</code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Returns the major, minor and build versions of the firmware as 
 +a 3-item list.</p></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def fw_version(self):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    ​Returns the major, minor and build versions of the firmware as  
 +    ​a 3-item list. 
 +    &#​34;&#​34;&#​34;​  
 +    return self.bus.read_i2c_block_data(self.addr,​ 3, 3)</code></pre> 
 +</details
 +</dd> 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.hw_version"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>​hw_version</​span></​span>​(<​span>​self)</span> 
 +</code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Returns the major and minor versions of the PCB as a 2-item list.</p></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def hw_version(self):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    ​Returns the major and minor versions of the PCB as a 2-item list. 
 +    &#​34;&#​34;&#​34;​  
 +    return self.bus.read_i2c_block_data(self.addr,​ 1, 2)</code></pre> 
 +</details
 +</dd> 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.io_bits"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>io_bits</​span></​span>​(<​span>​self, bits=None)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​Sets or gets the logic state of the IO bits 0 through 3, corresponding 
 +to pins 4 through 7 on Vizy's IO connector. 
 +The <​code>​bits</​code> ​argument ranges 
 +between 0 and 15 as it is a binary representation of the logic state 
 +of the 4 IO bits. 
 +If the <​code>​bits</​code> ​argument isn't specified, the logic 
 +state of the 4 bits are returned.</​p>​ 
 +<pre><​code>​io_bits(1) ​  # set IO bit 0 to logic 1 and bits 1, 2, 3 to logic 0
 io_bits(10) ​ # set IO bits 1 and 3 to logic 1 and bits 0 and 2 to logic 0 io_bits(10) ​ # set IO bits 1 and 3 to logic 1 and bits 0 and 2 to logic 0
 bits = io_bits() ​ # get logic state of IO bits bits = io_bits() ​ # get logic state of IO bits
 io_bits(io_bits()|1) ​ # set IO bit 0 to logic 1, leave bits 1, 2, 3 unchanged. io_bits(io_bits()|1) ​ # set IO bit 0 to logic 1, leave bits 1, 2, 3 unchanged.
-</​code><​HTML></dd></HTML+</​code><​/pre></div> 
-<HTML><dt></HTML>''​%%io_set_mode(self, bit, mode=None)%%''​<HTML></dt></HTML+<details class="​source"​
-<HTML><dd></HTML><HTML><p></HTML>Sets or gets the io mode of the given bit. The ''​%%bit%%'' ​argument ranges between 0 and 3 and corresponds to pins 4 through 7 on Vizys IO connector. Calling this method with no mode argument returns the mode of the given bit, otherwise, the ''​%%mode%%'' ​argument can be one of the following:<​HTML>​</p></​HTML+<summary> 
-<​HTML>​<ul></​HTML+<span>Expand source code</span> 
-<​HTML>​<li></​HTML>​IO_MODE_INPUT,​ sets the bit to high impedance input mode with a weak pull-up resistor to 3.3V. The input voltage can range between 0 and Vin where Vin is the supply voltage. Voltages lower than 1V read as logic 0 via ''​%%VizyPowerBoard.io_bits()%%''​. Voltages higher than 1V are read as logic 1.<​HTML>​</li></​HTML+</​summary>​ 
-<​HTML>​<li></​HTML>​IO_MODE_OUTPUT,​ sets the bit to output mode. If the bit is set to logic 0 via ''​%%VizyPowerBoard.io_bits()%%''​, the output voltage is 0V.\\ +<​pre><​code class="​python">​def io_bits(self, ​bits=None):​ 
-If the bit is set to logic 1, the output voltage is 3.3V. In this mode, each bit can source and sink 5mA.\\ +    &#​34;&#​34;&#​34;​ 
-<HTML></​li></​HTML+    Sets or gets the logic state of the IO bits 0 through 3, corresponding 
-<HTML><li></HTML>​IO_MODE_HIGH_CURRENT,​ sets the bit to a special high current mode that allows the bit to sink as much as 1000mA, when the bit set to logic 0 via ''​%%VizyPowerBoard.io_bits()%%''​. Otherwise, this mode behaves exactly as IO_MODE_OUTPUT.<​HTML>​</li></HTML><​HTML></ul></HTML+    to pins 4 through 7 on Vizy&#​39;​s IO connector. ​ The `bits` argument ranges 
-<HTML></dd></HTML> +    between 0 and 15 as it is a binary representation of the logic state 
-<HTML><dt></HTML>''​%%ir_filter(self, state=None, duration=None)%%''​<HTML></dt></HTML+    of the 4 IO bits.  If the `bits` argument isn&#​39;​t specified, the logic 
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>​Actuates the electro-mechanical IR-cut filter on Vizys camera. Vizy uses a CMOS sensor which is very sensitive to IR light. IR light can adversely affect color fidelity during the daytime so an IR-cut filter is used to block the IR light (''​%%state%%''​=True). During nighttime IR light is typically used as a discreet method of illumination and the IR-cut filter is removed (''​%%state%%''​=False). If the ''​%%state%%'' ​argument is ''​%%True%%''​, the filter is actuated in place (and will stay there) until another call is made with the state argument set to ''​%%False%%'' ​(in which case the IR-cut filter will be removed).<​HTML>​</p></​HTML+    state of the 4 bits are returned. 
-<HTML><p></HTML>The ''​%%duration%%'' ​argument is optional and controls how long (in milliseconds) the actuation coil receives power.<HTML></​p></​HTML+ 
-<HTML><p></HTML>Calling this method without arguments returns the state of IR-cut filter.<HTML></p></HTML><​HTML></​dd><​/HTML+        io_bits(1) ​  # set IO bit 0 to logic 1 and bits 12, 3 to logic 0 
-<HTML><dt></HTML>''​%%led(self, r=0, g=0, b=0, flashes=0, repeat=False,​ atten=255, on=100, off=100, pause=200)%%''​<HTML></dt></HTML+        io_bits(10) ​ # set IO bits 1 and 3 to logic 1 and bits 0 and 2 to logic 0 
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>​Controls the RGB LED in one of several modes:<​HTML>​</p></​HTML+        bits io_bits() ​ # get logic state of IO bits 
-<​HTML>​<​ul><​/HTML+        io_bits(io_bits()|1) ​ # set IO bit 0 to logic 1, leave bits 1, 2, 3 unchanged.  
-<HTML><li></HTML><HTML><p></HTML>**Continuous**:​ just setting ''​%%r%%'',​ ''​%%g%%''​, and ''​%%b%%'' ​will set set the LED color and turn it on continuously. ​''​%%r%%''​''​%%g%%''​, and ''​%%b%%'' ​values range between 0 and 255.<​HTML>​</​p><​/HTML> +    &#​34;&#​34;&#​34;​ 
-<​code>​ +    if bits is None
-  ​led(255, 0, 0)   # turn on LED, red color +        return self.bus.read_i2c_block_data(self.addr,​ 72, 1) 
-  led(255, 255, 0) # turn on LED, yellow color +    self.bus.write_i2c_block_data(self.addr,​ 72, [bits])</code></pre> 
-  led(0, 0, 255)   # turn on LED, blue color +</details
-  led(0, 0, 0)     # turn off LED +</dd> 
-</​code><​HTML></​li><​/HTML+<dt id="​vizypowerboard.VizyPowerBoard.io_set_mode"​><code class="​name flex">​ 
-<HTML><li></HTML><HTML><​p></HTML>**Flashes**:​ setting the ''​%%flashes%%'' ​value to a non-zero value will cause the LED to flash the indicated number of times. You can also specify the ''​%%on%%'' ​and ''​%%off%%'' ​arguments to indicate the amount of time the LED is on and off for each flash (specified in milliseconds).<​HTML>​</​p><​/HTML> +<​span>​def <span class="​ident">​io_set_mode</span></span>(<span>self, bit, mode=None)</span> 
-<​code>​ +</​code></​dt>​ 
-  ​led(0, 0, 255, 3)  # flash blue 3 times (then stop) +<​dd>​ 
-  led(0, 0, 255, 3, on=500, off=500) ​ # flash blue 3 times, much more slowly +<div class="​desc"><​p>Sets or gets the io mode of the given bit. 
-</​code><​HTML></li></​HTML+The <​code>​bit</​code> ​argument ranges 
-<​HTML>​<​li><​/​HTML><​HTML><p></HTML>**Repeated flashes**: setting the ''​%%repeat%%'' ​argument to ''​%%True%%'' ​will cause the indicated flash pattern to repeat forever. You can modify the pause time between flash sequences by setting ​''​%%pause%%'' ​(milliseconds).<​HTML>​</​p><​/HTML> +between 
-<​code>​ +0 and 3 and corresponds to pins 4 through 7 on Vizy's IO 
-  ​led(0, 0, 255, 3, True, pause=500) ​ # flash blue 3 times, pause, then repeat +connector. Calling this method with no mode argument returns the mode 
-  led(0, 0, 255, repeat=True,​ on=500, off=500)` ​ # flash blue forever +of the given bit, otherwise, the <​code>​mode</​code> ​argument can be one of 
-</​code><​HTML></li></​HTML+the following:</​p>​ 
-<​HTML>​<li></​HTML><​HTML>​<​p><​/HTML>**Flashing with attenuation**: you can also set the ''​%%atten%%'' ​argument to make the LED to turn on and off slowly, like an incandescent light. The value is the rate of change, so lower values cause the LED color to change more slowly.<​HTML>​</​p><​/HTML> +<​ul>​ 
-<​code>​ +<​li>​IO_MODE_INPUT,​ sets the bit to high impedance input mode with 
-  ​led(0, 0, 255, repeat=True,​ atten=10, on=500, off=500) # flash blue forever, but turn on and turn off very slowly +a weak pull-up resistor to 3.3V. 
-</​code><​HTML></​li></​HTML><HTML></ul></HTML+The input voltage can range between 
-<HTML></dd></HTML+0 and Vin where Vin is the supply voltage. 
-<HTML><​dt><​/HTML>''​%%led_background(self,​ r=-1, g=-1, b=-1)%%''​<HTML></dt></HTML+Voltages lower than 1V 
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>​The ​background” LED color is the color of the LED when the LED is turned ​off. It is used by system programs such as vizy-powerd to indicate Vizys system state such as, booting (yellow), finished booting (green), running server (blue), etc. Note, the background color does not influence the LED colors set by calls to led().<​HTML>​</p></​HTML+read as logic 0 via <​code><​a title="​vizypowerboard.VizyPowerBoard.io_bits"​ href="#​vizypowerboard.VizyPowerBoard.io_bits">​VizyPowerBoard.io_bits()</​a></​code>​. 
-<​HTML>​<p></​HTML>Calling led_background() without arguments returns the current background color r, g, and b values in a list.<​HTML>​</​p><​/HTML> +Voltages higher 
-<​code>​ +than 1V are read as logic 1.</​li>​ 
-led_background(48,​ 48, 0)  # set background color to yellow+<​li>​IO_MODE_OUTPUT,​ sets the bit to output mode. 
 +If the bit is set to 
 +logic 0 via <​code><​a title="​vizypowerboard.VizyPowerBoard.io_bits"​ href="#​vizypowerboard.VizyPowerBoard.io_bits">​VizyPowerBoard.io_bits()</​a></​code>​, the output voltage is 0V.<br> 
 +If the bit is set to logic 1, the output voltage is 3.3V. 
 +In this mode, each bit can source and sink 5mA. 
 +</li> 
 +<​li>​IO_MODE_HIGH_CURRENT,​ sets the bit to a special high current mode 
 +that allows the bit to sink as much as 1000mA, when the bit 
 +set to logic 0 via <​code><​a title="​vizypowerboard.VizyPowerBoard.io_bits"​ href="#​vizypowerboard.VizyPowerBoard.io_bits">​VizyPowerBoard.io_bits()</​a></​code>​. 
 +Otherwise, this mode 
 +behaves exactly as IO_MODE_OUTPUT.</li> 
 +</ul></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def io_set_mode(self,​ bit, mode=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    Sets or gets the io mode of the given bit.  The `bit` argument ranges 
 +    between ​ 0 and 3 and corresponds to pins 4 through 7 on Vizy&#​39;​s IO 
 +    connector. Calling this method with no mode argument returns the mode 
 +    of the given bit, otherwise, the `mode` argument can be one of  
 +    the following:​ 
 + 
 +    * IO_MODE_INPUT,​ sets the bit to high impedance input mode with  
 +    a weak pull-up resistor to 3.3V.  The input voltage can range between 
 +    0 and Vin where Vin is the supply voltage. ​ Voltages lower than 1V  
 +    read as logic 0 via `VizyPowerBoard.io_bits()`. ​ Voltages higher  
 +    than 1V are read as logic 1. 
 +    * IO_MODE_OUTPUT,​ sets the bit to output mode.  If the bit is set to 
 +    logic 0 via `VizyPowerBoard.io_bits()`,​ the output voltage is 0V.   
 +    If the bit is set to logic 1, the output voltage is 3.3V.  In this mode, each bit can source and sink 5mA.   
 +    * IO_MODE_HIGH_CURRENT,​ sets the bit to a special high current mode 
 +    ​that allows the bit to sink as much as 1000mA, when the bit  
 +    ​set to logic 0 via `VizyPowerBoard.io_bits()` Otherwise, this mode 
 +    ​behaves exactly as IO_MODE_OUTPUT. ​    
 +    &#​34;&#​34;&#​34;​ 
 +    if mode is None: 
 +        return self.bus.read_i2c_block_data(self.addr,​ 68+bit, 1)[0] 
 +    if bit==2: 
 +        # set GPIO14 (UART TXD) as input so it doesn&#​39;​t conflict 
 +        GPIO.setwarnings(False) 
 +        GPIO.setmode(GPIO.BOARD) 
 +        GPIO.setup(8,​ GPIO.IN) 
 +    self.bus.write_i2c_block_data(self.addr,​ 68+bit, [self._u_int8(mode)])</code></pre> 
 +</details> 
 +</dd
 +<dt id="​vizypowerboard.VizyPowerBoard.ir_filter"​><code class="​name flex"> 
 +<span>def <span class="​ident"​>ir_filter</span></span>(<​span>​self, state=None, duration=None)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​Actuates the electro-mechanical IR-cut filter on Vizy's camera. 
 +Vizy 
 +uses a CMOS sensor which is very sensitive to IR light. 
 +IR light can 
 +adversely affect color fidelity during the daytime so an IR-cut filter 
 +is used to block the IR light (<​code>​state</​code>​=True). 
 +During nighttime IR light 
 +is typically used as a discreet method of illumination and the IR-cut 
 +filter is removed (<​code>​state</​code>​=False). 
 +If the <​code>​state</​code> ​argument is <​code>​True</​code>​, 
 +the filter is actuated in place (and will stay there) until another 
 +call is made with the state argument set to <​code>​False</​code> ​(in which case the 
 +IR-cut filter will be removed). 
 +</​p>​ 
 +<p>The <code>duration</code> argument is optional and 
 +controls how long (in milliseconds) the actuation coil receives power.</p> 
 +<​p>​Calling this method without arguments returns the state of IR-cut 
 +filter.</​p></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def ir_filter(self,​ state=None, duration=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    Actuates the electro-mechanical IR-cut filter on Vizy&#​39;​s camera. ​ Vizy 
 +    uses a CMOS sensor which is very sensitive to IR light. ​ IR light can  
 +    adversely affect color fidelity during the daytime so an IR-cut filter 
 +    is used to block the IR light (`state`=True). ​ During nighttime IR light 
 +    is typically used as a discreet method of illumination and the IR-cut 
 +    filter is removed (`state`=False). ​ If the `state` argument is `True`, 
 +    the filter is actuated in place (and will stay there) until another 
 +    call is made with the state argument set to `False` (in which case the 
 +    IR-cut filter will be removed). ​  
 + 
 +    The `duration` argument is optional and 
 +    controls how long (in milliseconds) the actuation coil receives power. 
 + 
 +    ​Calling this method without arguments returns the state of IR-cut 
 +    ​filter. 
 +    &#​34;&#​34;&#​34;​ 
 +    if state is None: 
 +        return True if self.bus.read_i2c_block_data(self.addr,​ 73, 1)[0] else False 
 +    data = [1] if state else [0] 
 +    if duration is not None: 
 +        data.append(int(duration/​10)) 
 +    self.bus.write_i2c_block_data(self.addr,​ 73, data)</code></pre> 
 +</details> 
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.led"><​code class="​name flex"
 +<span>def <span class="​ident"​>led</span></​span>(<​span>​self, r=0, g=0, b=0, flashes=0, repeat=False,​ atten=255, on=100, off=100, pause=200)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​Controls the RGB LED in one of several modes:</​p>​ 
 +<ul> 
 +<li
 +<p><strong>Continuous</strong>: just setting ​<code>r</code>, <​code>​g</code>, and <​code>​b</​code> ​will set set the LED color 
 +and turn it on continuously. 
 +<​code>​r</​code>​<​code>​g</​code>​, and <​code>​b</​code> ​values range between 0 
 +and 
 +255.</​p>​ 
 +<pre><​code>​led(255,​ 0, 0)   # turn on LED, red color 
 +led(255, 255, 0) # turn on LED, yellow color 
 +led(0, 0, 255)   # turn on LED, blue color 
 +led(0, 0, 0)     # turn off LED 
 +</​code><​/pre> 
 +</li> 
 +<li
 +<p><strong>Flashes</strong>: setting the <code>flashes</code> value to a non-zero value will 
 +cause the LED to flash the indicated number of times. 
 +You can also 
 +specify the <​code>​on</​code> ​and <​code>​off</​code> ​arguments to indicate the amount of time 
 +the LED is on and off for each flash (specified in milliseconds).</​p>​ 
 +<pre><​code>​led(0,​ 0, 255, 3)  # flash blue 3 times (then stop) 
 +led(0, 0, 255, 3, on=500, off=500) ​ # flash blue 3 times, much more slowly 
 +</​code><​/pre> 
 +</​li>​ 
 +<li> 
 +<p><strong>Repeated flashes</strong>: setting the <​code>​repeat</​code> ​argument to <​code>​True</​code>​ 
 +will cause the indicated flash pattern to repeat forever. 
 +You can 
 +modify the pause time between flash sequences by setting ​<​code>​pause</​code>​ 
 +(milliseconds).</​p>​ 
 +<pre><​code>​led(0,​ 0, 255, 3, True, pause=500) ​ # flash blue 3 times, pause, then repeat 
 +led(0, 0, 255, repeat=True,​ on=500, off=500)` ​ # flash blue forever 
 +</​code><​/pre> 
 +</​li>​ 
 +<li> 
 +<​p><​strong>​Flashing with attenuation</​strong>​: you can also set the <​code>​atten</​code>​ 
 +argument to make the LED to turn on and off slowly, like an 
 +incandescent light. 
 +The value is the rate of change, so lower values 
 +cause the LED color to change more slowly. </p> 
 +<pre><​code>​led(0,​ 0, 255, repeat=True,​ atten=10, on=500, off=500) # flash blue forever, but turn on and turn off very slowly 
 +</​code><​/pre> 
 +</li> 
 +</ul></div> 
 +<details class="​source">​ 
 +<​summary>​ 
 +<​span>​Expand source code</span> 
 +</summary
 +<pre><code class="​python">​def led(self, r=0, g=0, b=0, flashes=0, repeat=False,​ atten=255, on=100, off=100, pause=200):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    Controls the RGB LED in one of several modes: 
 + 
 +    * **Continuous**:​ just setting `r`, `g`, and `b` will set set the LED color 
 +    and turn it on continuously. ​ `r`, `g`, and `b` values range between 0  
 +    and  255. 
 + 
 +            led(255, 0, 0)   # turn on LED, red color 
 +            led(255, 255, 0) # turn on LED, yellow color 
 +            led(0, 0, 255)   # turn on LED, blue color 
 +            led(0, 0, 0)     # turn off LED 
 + 
 +    * **Flashes**:​ setting the `flashes` value to a non-zero value will 
 +    cause the LED to flash the indicated number of times. ​ You can also 
 +    specify the `on` and `off` arguments to indicate the amount of time  
 +    the LED is on and off for each flash (specified in milliseconds). 
 + 
 +            led(0, 0, 255, 3)  # flash blue 3 times (then stop) 
 +            led(0, 0, 255, 3, on=500, off=500) ​ # flash blue 3 times, much more slowly 
 + 
 +    * **Repeated flashes**: setting the `repeat` argument to `True`  
 +    will cause the indicated flash pattern to repeat forever. ​ You can 
 +    modify the pause time between flash sequences by setting `pause` 
 +    (milliseconds). 
 + 
 +            led(0, 0, 255, 3, True, pause=500) ​ # flash blue 3 times, pause, then repeat 
 +            led(0, 0, 255, repeat=True,​ on=500, off=500)` ​ # flash blue forever 
 + 
 +    * **Flashing with attenuation**:​ you can also set the `atten`  
 +    argument to make the LED to turn on and off slowly, like an 
 +    incandescent light. ​ The value is the rate of change, so lower values 
 +    cause the LED color to change more slowly.  
 + 
 +            led(0, 0, 255, repeat=True,​ atten=10, on=500, off=500) # flash blue forever, but turn on and turn off very slowly 
 +    &#​34;&#​34;&#​34;​ 
 +    on = self._u_int8(on/10) 
 +    off = self._u_int8(off/​10) 
 +    pause = self._u_int8(pause/​10) 
 +    if flashes==0:​ 
 +        mode = 0 
 +    if repeat: 
 +        mode = 0x02 
 +    else: 
 +        mode = 0x01 
 +    self.bus.write_i2c_block_data(self.addr,​ 49, [mode, self._u_int8(r),​ self._u_int8(g),​ self._u_int8(b),​ 
 +        on, off, self._u_int8(flashes),​ pause, self._u_int8(atten)])</​code></pre
 +</details> 
 +</​dd>​ 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.led_background"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>​led_background</​span></​span>​(<​span>​self, r=-1, g=-1, b=-1)</span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​The ​"background" ​LED color is the color of the LED when the LED is 
 +turned ​"off". 
 +It is used by system programs such as vizy-powerd to 
 +indicate Vizy's system state such as, booting (yellow), finished 
 +booting (green), running server (blue), etc. 
 +Note, the background 
 +color does not influence the LED colors set by calls to led().</​p>​ 
 +<​p>​Calling led_background() without arguments returns the current 
 +background color r, g, and b values in a list. </p> 
 +<pre><​code>​led_background(48,​ 48, 0)  # set background color to yellow
 led(0, 255, 0)  # turn on LED, green (as expected) led(0, 255, 0)  # turn on LED, green (as expected)
 led(0, 0, 0)  # turn LED off, and restore background color (yellow as set previously) led(0, 0, 0)  # turn LED off, and restore background color (yellow as set previously)
-</​code><​HTML></dd></HTML+</​code><​/pre></div> 
-<HTML><dt></HTML>''​%%led_unicorn(self,​ speed=10)%%''​<HTML></dt></HTML+<details class="​source">​ 
-<HTML><dd></HTML>This causes the LED to change color in succession: red, orange, yellow, green, cyan, blue, violet and then repeat again. The ''​%%speed%%'' ​argument ranges between 0 and 10. For example, a ''​%%speed%%'' ​of 0 causes the color to change once every couple of seconds. A ''​%%speed%%'' ​of 10 causes the color to change about 6 times per second.<HTML></dd></HTML+<​summary>​ 
-<HTML><dt></HTML>''​%%measure(self, ​channel)%%''​<HTML></dt></HTML+<​span>​Expand source code</span
-<HTML><dd></HTML><HTML><p></HTML>Get the voltage values of various channels. The returned value is the voltage measured (in Volts) of the given channel. The ''​%%channel%%'' ​argument can be one of the following:<​HTML>​</p></​HTML+</summary> 
-<​HTML>​<ul></​HTML+<pre><code class="​python">​def led_background(self,​ r=-1, g=-1, b=-1): 
-<​HTML>​<li></​HTML>​CHANNEL_VIN,​ this channel measures the voltage present at the 12V power input.<HTML></​li></​HTML+    &#​34;&#​34;&#​34;​ 
-<HTML><li></HTML>​CHANNEL_5V,​ this channel measures the voltage present at the 5V voltage rail provided to the Raspberry Pi.<​HTML>​</li></HTML><​HTML></ul></HTML+    The &#​34;​background&#​34;​ LED color is the color of the LED when the LED is  
-<HTML></dd></HTML> +    turned &#​34;​off&#​34;​. ​ It is used by system programs such as vizy-powerd to 
-<HTML><dt></HTML>''​%%power_off(self, t=5000)%%''​<HTML></dt></HTML+    indicate Vizy&#​39;​s system state such as, booting (yellow), finished 
-<HTML><dd></HTML>Powers Vizy off. The ''​%%t%%'' ​argument specifies how long to wait before turning off (specified in milliseconds). The vizy-powerd service calls this upon shutdown.<​HTML></dd></HTML+    booting (green), running server (blue), etc.  Note, the background 
-<HTML><dt></HTML>''​%%power_off_requested(self)%%''​<HTML></dt></HTML+    color does not influence the LED colors set by calls to led(). 
-<HTML><dd></HTML><HTML><p></HTML>​Returns ​''​%%True%%'' ​if Vizys button is held down for more than 5 seconds indicating that the user wishes to initiate safe shutdown and power off. Returns ​''​%%False%%'' ​otherwise.<​HTML></​p></​HTML+ 
-<HTML><p></HTML>This is used by the vizy-powerd service.<​HTML></p></HTML><​HTML></​dd><​/HTML+    Calling led_background() without arguments returns the current  
-<HTML><dt></HTML>''​%%power_on_alarm_date(self, datetime_=None)%%''​<HTML></dt></HTML+    background color r, g, and b values in a list.  
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>If you wish to power off your Vizy and have it wake up” at a specified time and date, call this method with the desired datetime object and initiate a shutdown. (e.g. ''​%%sudo shutdown now%%''​).<​HTML>​</p></​HTML+ 
-<​HTML>​<p></​HTML>The code below tells Vizy to turn on on December 2, 2022, 1:18pm.<​HTML>​</​p><​/HTML> +        led_background(48,​ 48, 0)  # set background color to yellow 
-<​code>​ +        led(0, 255, 0)  # turn on LED, green (as expected) 
-import vizypowerboard as vpb+        led(0, 0, 0)  # turn LED off, and restore background color (yellow as set previously) ​    
 +    &#​34;&#​34;&#​34;​ 
 +    if r==-1: 
 +        return self.bus.read_i2c_block_data(self.addr,​ 58, 3) 
 +    self.bus.write_i2c_block_data(self.addr,​ 58, [self._u_int8(r),​ self._u_int8(g),​ self._u_int8(b)])</code></​pre>​ 
 +</​details>​ 
 +</​dd>​ 
 +<dt id="​vizypowerboard.VizyPowerBoard.led_unicorn"><​code class="​name flex">​ 
 +<​span>​def <span class="​ident">​led_unicorn</​span></​span>​(<​span>​self, speed=10)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><p>This causes the LED to change color in succession: red, orange, yellow, 
 +green, cyan, blue, violet and then repeat again. 
 +The <​code>​speed</​code> ​argument 
 +ranges between 0 and 10. 
 +For example, a <​code>​speed</​code> ​of 0 causes the color 
 +to change once every couple of seconds. 
 +<​code>​speed</​code> ​of 10 causes the color to change about 6 times per second.</p></div> 
 +<details class="​source"​
 +<summary> 
 +<span>Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def led_unicorn(self, ​speed=10):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    This causes the LED to change color in succession: red, orange, yellow,  
 +    green, cyan, blue, violet and then repeat again. ​ The `speed` argument  
 +    ranges between 0 and 10.  For example, a `speed` of 0 causes the color  
 +    to change once every couple of seconds. ​ A `speed` of 10 causes the color to change about 6 times per second. 
 +    &#​34;&#​34;&#​34;​ 
 +    if speed&​gt;​10:​ 
 +        speed = 10 
 +    elif speed&​lt;​0:​ 
 +        speed = 0 
 + 
 +    on = self._u_int8(10 + (10-speed)*140/​10) 
 +    atten = self._u_int8(3 + speed*47/​10) ​    
 +    self.bus.write_i2c_block_data(self.addr,​ 49, [0x08, 0, 0, 0, on, 0, 0, 0, atten])</code></pre> 
 +</details
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.measure"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident">​measure</span></span>(<span>self, channel)</span> 
 +</​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>Get the voltage values of various channels. 
 +The returned value is 
 +the voltage measured (in Volts) of the given channel. 
 +The <​code>​channel</​code>​ 
 +argument can be one of the following:</​p>​ 
 +<​ul>​ 
 +<​li>​CHANNEL_VIN,​ this channel measures the voltage present at the 12V 
 +power input.</li> 
 +<​li>​CHANNEL_5V,​ this channel measures the voltage present at the 5V 
 +voltage rail provided to the Raspberry Pi.</li> 
 +</ul></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def measure(self,​ channel): 
 +    &#​34;&#​34;&#​34;​ 
 +    Get the voltage values of various channels. ​ The returned value is  
 +    the voltage measured (in Volts) of the given channel. ​ The `channel` 
 +    argument can be one of the following:​ 
 + 
 +    * CHANNEL_VIN,​ this channel measures the voltage present at the 12V 
 +    power input. 
 +    * CHANNEL_5V, this channel measures the voltage present at the 5V 
 +    ​voltage rail provided to the Raspberry Pi. 
 +    &#​34;&#​34;&#​34; ​  
 +    self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_AD, self._u_int8(channel)]) 
 +    # Wait until it&#​39;​s ready. 
 +    self._wait_until_not_busy() 
 +    val = self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+2,​ 2) 
 +    return (val[1]*0x100 + val[0])/​1000</code></pre> 
 +</details> 
 +</dd
 +<dt id="​vizypowerboard.VizyPowerBoard.power_off"​><code class="​name flex"> 
 +<span>def <span class="​ident"​>power_off</span></span>(<​span>​self, t=5000)</span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><p>Powers Vizy off. The <​code>​t</​code> ​argument specifies how long 
 +to wait before turning off (specified in milliseconds). 
 +The 
 +vizy-powerd service calls this upon shutdown.<​/p></div> 
 +<details class="​source"​
 +<summary> 
 +<span>Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def power_off(self, t=5000): 
 +    &#​34;&#​34;&#​34;​ 
 +    Powers Vizy off. The `t` argument specifies how long  
 +    to wait before turning off (specified in milliseconds). ​ The  
 +    vizy-powerd service calls this upon shutdown. 
 +    &#​34;&#​34;&#​34;​ 
 +    self.bus.write_i2c_block_data(self.addr,​ 38, [0x1f, int(t/100)])</code></pre> 
 +</details
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.power_off_requested"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident">​power_off_requested</span></span>(<span>self)</span> 
 +</​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​Returns ​<​code>​True</​code> ​if Vizy's button is held down for more than 5 seconds 
 +indicating that the user wishes to initiate safe shutdown and power 
 +off. 
 +Returns ​<​code>​False</​code> ​otherwise.<​/p> 
 +<​p>​This is used by the vizy-powerd service.</​p></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def power_off_requested(self):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    Returns `True` if Vizy&#​39;​s button is held down for more than 5 seconds 
 +    indicating that the user wishes to initiate safe shutdown and power 
 +    off.  Returns `False` otherwise. 
 + 
 +    ​This is used by the vizy-powerd service. ​ 
 +    &#​34;&#​34;&#​34;​ 
 +    button = self.bus.read_i2c_block_data(self.addr,​ 38, 1) 
 +    if button[0]==0x0f:​ 
 +        return True 
 +    else: 
 +        return False</code></pre> 
 +</details> 
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.power_on_alarm_date"><​code class="​name flex"
 +<span>def <span class="​ident"​>power_on_alarm_date</span></​span>(<​span>​self, datetime_=None)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​If you wish to power off your Vizy and have it "wake up" ​at a 
 +specified time and date, call this method with the desired 
 +datetime object and initiate a shutdown. (e.g. <​code>​sudo shutdown now</​code>​).</​p>​ 
 +<​p>​The code below tells Vizy to turn on on December 2, 2022, 11:18am.</p> 
 +<pre><​code>​import vizypowerboard as vpb
 from datetime import datetime from datetime import datetime
 v = vpb.VizyPowerBoard() v = vpb.VizyPowerBoard()
-d=datetime(year=2022,​ month=12, day=2, hour=13, minute=18, second=0)+d=datetime(year=2022,​ month=12, day=2, hour=11, minute=18, second=0)
 v.power_on_alarm_date(d) v.power_on_alarm_date(d)
-</​code>​ +</code></​pre
-<HTML><p></HTML>Argsdatetime_ (datetime, optional, default=None): ''​%%datetime%%'' ​object that specifies the date/time to wake up” (turn on).<​HTML>​</p></HTML+<h2 id="​args"​>Args</h2> 
-<HTML><p></HTML>Returns: ​Calling without a datetime object returns a ''​%%datetime%%'' ​object reflecting the active alarm time. If there is no active alarm, ​''​%%None%%'' ​is returned.<​HTML></p></HTML+<​dl>​ 
-<HTML><p></HTML>Notes: * Once setting the alarm date, Vizy will retain it even if Vizy loses power for extended periods of time. * If the alarm expires while Vizy is on, Vizy will emit a buzzer tone and remain on. * If the alarm expires while Vizy is off (but plugged into and receiving power), Vizy will turn on. * If the alarm expires while Vizy is unplugged from (or not receiving) power, Vizy will turn on as soon as it receives power.<HTML></p></HTML><​HTML></​dd><​/HTML+<​dt><​strong><​code>​datetime_</code></​strong> :&​ensp;<​code>​datetime</​code>​, optional, default=<​code>​None</​code></​dt>​ 
-<HTML><dt></HTML>''​%%power_on_alarm_seconds(self, seconds=None)%%''​<HTML></dt></HTML+<​dd><​code>​datetime</​code> ​object that 
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>Allows you to specify a power on alarm in seconds in the future. For example, if you wish for Vizy to turn back on in 5 minutes, you would call ''​%%power_on_alarm_seconds(300)%%'' ​and then initiate a shutdown. See ''​%%VizyPowerBoard.power_on_alarm_date()%%'' ​for more information about the power on alarm.<​HTML>​</​p></​HTML+specifies the date/time to "wake up" ​(turn on).</dd> 
-<HTML><p></HTML>Argsseconds (integer, optional, default=None): Number of seconds in the future you wish Vizy to turn on in.<HTML></p></HTML+</dl
-<HTML><​p></​HTML>​Returns:​ Calling this method without arguments returns the number of seconds until the alarm expires. If no alarm is pending, ​''​%%None%%'' ​is returned.<​HTML></p></HTML><​HTML></​dd><​/HTML+<h2 id="​returns"​>Returns</h2> 
-<HTML><dt></HTML>''​%%power_on_source(self)%%''​<HTML></dt></HTML+<p>Calling without a datetime object returns a <​code>​datetime</​code> ​object 
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>Returns the source of what turned on Vizy for the current power cycle. It is one of either:<​HTML>​</p></​HTML+reflecting the active alarm time. 
-<​HTML>​<ul></​HTML+If there is no active alarm, 
-<​HTML>​<li></​HTML>​POWER_ON_SOURCE_ALARM,​ indicates that Vizy was powered on by the power on alarm expiring. See power_on_alarm_date() and power_on_alarm_seconds().<​HTML>​</li></​HTML+<​code>​None</​code> ​is returned.<​/p> 
-<​HTML>​<li></​HTML>​POWER_ON_SOURCE_POWER_BUTTON,​ indicates that Vizy was powered on by someone pressing the button.<​HTML>​</li></​HTML+<h2 id="​notes">​Notes</h2> 
-<​HTML>​<li></​HTML>​POWER_ON_SOURCE_12V = indicates that Vizy was powered on by power being applied to 12V power input. This only applies if the dip switch power mode allows powering on by plugging in power via the 12V power input.<HTML></​li></​HTML+<​ul>​ 
-<HTML><li></HTML>​POWER_ON_SOURCE_5V,​ indicates that Vizy was powered on by applying power to the Raspberry Pis USB-C power input.<HTML></li></HTML><HTML></ul></HTML+<​li>​Once setting the alarm date, Vizy will retain it even if Vizy loses 
-<HTML></dd></HTML+power for extended periods of time.</li
-<HTML><​dt><​/HTML>''​%%resource_url(self)%%''​<HTML></dt></HTML+<li>If the alarm expires while Vizy is on, Vizy will emit a buzzer tone 
-<HTML><dd></HTML>Returns the url of a JSON file that contains information about resources, such as the location of the latest version of this code, latest firmware, etc.<HTML></dd></HTML+and remain on.</li> 
-<HTML><​dt><​/HTML>''​%%rtc(self, datetime_=None)%%''​<HTML></dt></HTML+<​li>​If the alarm expires while Vizy is off (but plugged into and 
-<​HTML>​<​dd><​/​HTML><​HTML><p></​HTML>Set or get the real-time clock time/date. The Vizy power board has a battery-backed real-time clock that keeps track of time/date, power alarms, etc. even while Vizy is receiving no power. Passing in a datetime object sets the time/date.<​HTML>​</p></​HTML+receiving power), Vizy will turn on.</li> 
-<​HTML>​<p></​HTML>Calling this method with no arguments returns a datetime object representing the current date/time.<​HTML>​</p></​HTML+<​li>​If the alarm expires while Vizy is unplugged from (or not receiving) 
-<​HTML>​<p></​HTML>For example, the code below sets the date to December 2, 2020, 1:18pm:<​HTML>​</​p><​/HTML> +power, Vizy will turn on as soon as it receives power.</​li>​ 
-<​code>​ +</​ul></​div>​ 
-from datetime import datetime+<details class="​source">​ 
 +<​summary>​ 
 +<​span>​Expand source code</​span>​ 
 +</​summary>​ 
 +<​pre><​code class="​python">​def power_on_alarm_date(self,​ datetime_=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    If you wish to power off your Vizy and have it &#​34;​wake up&#34; at a 
 +    specified time and date, call this method with the desired 
 +    datetime object and initiate a shutdown. (e.g. `sudo shutdown now`). 
 + 
 + 
 +    The code below tells Vizy to turn on on December 2, 2022, 11:18am. 
 + 
 +        import vizypowerboard as vpb 
 +        from datetime import datetime 
 +        v = vpb.VizyPowerBoard() 
 +        d=datetime(year=2022,​ month=12, day=2, hour=11, minute=18, second=0) 
 +        v.power_on_alarm_date(d) 
 + 
 +    Args: 
 +      datetime_ (datetime, optional, default=None):​ `datetime` object that 
 +        specifies the date/time to &#​34;​wake up&#34; (turn on). 
 + 
 +    Returns: 
 +      Calling without a datetime object returns a `datetime` object  
 +      reflecting the active alarm time.  If there is no active alarm, 
 +      `None` is returned. 
 +        
 +    ​Notes: 
 +      ​* Once setting the alarm date, Vizy will retain it even if Vizy loses 
 +      ​power for extended periods of time. 
 +      ​* If the alarm expires while Vizy is on, Vizy will emit a buzzer tone 
 +      ​and remain on. 
 +      ​* If the alarm expires while Vizy is off (but plugged into and 
 +      ​receiving power), Vizy will turn on. 
 +      ​* If the alarm expires while Vizy is unplugged from (or not receiving) 
 +      ​power, Vizy will turn on as soon as it receives power. ​  
 +    &#​34;&#​34;&#​34;​ 
 +    if datetime_ is None: 
 +        t = self.bus.read_i2c_block_data(self.addr,​ 41, 6) 
 +        if t[5]==0: 
 +            return None 
 +        return datetime.datetime(year=self._bcd2decimal(t[5])+2016,​ month=self._bcd2decimal(t[4]),​ day=self._bcd2decimal(t[3]),​ hour=self._bcd2decimal(t[2]),​ minute=self._bcd2decimal(t[1]),​ second=self._bcd2decimal(t[0])) 
 +    t = [self._decimal2bcd(datetime_.second),​ self._decimal2bcd(datetime_.minute),​ self._decimal2bcd(datetime_.hour),​ self._decimal2bcd(datetime_.day),​ self._decimal2bcd(datetime_.month),​ self._decimal2bcd(datetime_.year-2016)] 
 +    self.bus.write_i2c_block_data(self.addr,​ 41, t)</code></pre> 
 +</details> 
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.power_on_alarm_seconds"><​code class="​name flex"
 +<span>def <span class="​ident"​>power_on_alarm_seconds</span></​span>(<​span>​self, seconds=None)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​Allows you to specify a power on alarm in seconds in the future. 
 +For example, if you wish for Vizy to turn back on in 5 minutes, you 
 +would call <​code>​power_on_alarm_seconds(300)</​code> ​and then initiate a shutdown. 
 +See <​code><​a title="​vizypowerboard.VizyPowerBoard.power_on_alarm_date"​ href="#​vizypowerboard.VizyPowerBoard.power_on_alarm_date">​VizyPowerBoard.power_on_alarm_date()</​a></​code> ​for more information about the power on 
 +alarm.</​p>​ 
 +<h2 id="​args">​Args</h2
 +<dl> 
 +<dt><​strong><​code>​seconds</code></​strong> :&​ensp;<​code>​integer</​code>​, optional, default=<​code>​None</​code></​dt>​ 
 +<dd>Number of seconds in the 
 +future you wish Vizy to turn on in.</dd> 
 +</dl> 
 +<h2 id="​returns">​Returns</h2
 +<p>Calling this method without arguments returns the number of seconds 
 +until the alarm expires. 
 +If no alarm is pending, ​<code>​None</​code>​ is returned.</​p></div> 
 +<details class="​source">​ 
 +<​summary>​ 
 +<​span>​Expand source code</​span>​ 
 +</​summary>​ 
 +<​pre><​code class="​python">​def power_on_alarm_seconds(self,​ seconds=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    Allows you to specify a power on alarm in seconds in the future.  
 +    For example, if you wish for Vizy to turn back on in 5 minutes, you 
 +    would call `power_on_alarm_seconds(300)` and then initiate a shutdown. 
 +    See `VizyPowerBoard.power_on_alarm_date()` for more information about the power on  
 +    alarm. 
 + 
 +    Args: 
 +      seconds (integer, optional, default=None):​ Number of seconds in the 
 +        future you wish Vizy to turn on in. 
 + 
 +    ​Returns: 
 +      ​Calling this method without arguments returns the number of seconds 
 +      ​until the alarm expires. ​ If no alarm is pending, ​`Noneis returned. 
 +    &#​34;&#​34;&#​34;​ 
 +    if seconds is None: 
 +        pod = self.power_on_alarm_date() 
 +        if pod is None: 
 +            return None 
 +        diff = pod - self.rtc() 
 +        return diff.days*86400+diff.seconds  
 +    # Add seconds to current time and set power on alarm     
 +    self.power_on_alarm_date(self.rtc()+datetime.timedelta(seconds=seconds))</code></pre> 
 +</details> 
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.power_on_source"><​code class="​name flex"
 +<span>def <span class="​ident"​>power_on_source</span></​span>(<​span>​self)</span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​Returns the source of what turned on Vizy for the current power cycle. 
 +It is one of either:</​p>​ 
 +<​ul>​ 
 +<​li>​POWER_ON_SOURCE_ALARM,​ indicates that Vizy was powered on 
 +by the power on alarm expiring. 
 +See power_on_alarm_date() and 
 +power_on_alarm_seconds().</​li>​ 
 +<​li>​POWER_ON_SOURCE_POWER_BUTTON,​ indicates that Vizy was powered 
 +on by someone pressing the button.</​li>​ 
 +<​li>​POWER_ON_SOURCE_12V = indicates that Vizy was powered on 
 +by power being applied to 12V power input. 
 +This only applies if the 
 +dip switch power mode allows powering on by plugging in power via the 
 +12V power input.</li> 
 +<​li>​POWER_ON_SOURCE_5V,​ indicates that Vizy was powered on by applying 
 +power to the Raspberry Pi's USB-C power input.</li> 
 +</ul></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def power_on_source(self):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    Returns the source of what turned on Vizy for the current power cycle. 
 +    It is one of either: 
 + 
 +    * POWER_ON_SOURCE_ALARM,​ indicates that Vizy was powered on 
 +    by the power on alarm expiring. ​ See power_on_alarm_date() and 
 +    power_on_alarm_seconds(). 
 +    * POWER_ON_SOURCE_POWER_BUTTON,​ indicates that Vizy was powered  
 +    on by someone pressing the button. 
 +    * POWER_ON_SOURCE_12V = indicates that Vizy was powered on 
 +    by power being applied to 12V power input. ​ This only applies if the 
 +    dip switch power mode allows powering on by plugging in power via the 
 +    12V power input. 
 +    * POWER_ON_SOURCE_5V,​ indicates that Vizy was powered on by applying 
 +    ​power to the Raspberry Pi&#39;s USB-C power input. 
 +    &#​34;&#​34;&#​34;​ 
 +    source = self.bus.read_i2c_block_data(self.addr,​ 40, 1)[0] 
 +    return source</code></pre> 
 +</details> 
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.resource_url"​><code class="​name flex"
 +<span>def <span class="​ident">​resource_url</span></span>​(<​span>​self)</​span
 +</code></dt> 
 +<dd> 
 +<div class="​desc"​><​p>​Returns the url of a JSON file that contains information about 
 +resources, such as the location of the latest version of this code, 
 +latest firmware, etc.</p></div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def resource_url(self):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    ​Returns the url of a JSON file that contains information about  
 +    ​resources, such as the location of the latest version of this code,  
 +    ​latest firmware, etc. 
 +    &#​34;&#​34;&#​34;​ 
 +    chars = self.bus.read_i2c_block_data(self.addr,​ 6, 32) 
 +    s = &#​39;&#​39;​ 
 +    for c in chars: 
 +        if c==0: # read up to the null character 
 +            break 
 +        s += chr(c) 
 +    return s</code></pre> 
 +</details
 +</dd> 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.rtc"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>rtc</​span></​span>​(<​span>​self, datetime_=None)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><​p>​Set or get the real-time clock time/date. 
 +The Vizy power board has a 
 +battery-backed real-time clock that keeps track of time/date, power 
 +alarms, etc. even while Vizy is receiving no power. 
 +Passing in a 
 +datetime object sets the time/date. 
 +</​p>​ 
 +<​p>​Calling this method with no 
 +arguments returns a datetime object representing the current 
 +date/time. </​p>​ 
 +<​p>​For example, the code below sets the date to December 2, 2020, 11:18am:</p> 
 +<pre><​code>​from datetime import datetime
 import vizypowerboard as vpb import vizypowerboard as vpb
 v = vpb.VizyPowerBoard() v = vpb.VizyPowerBoard()
-t = datetime(year=2020,​ month=12, day=2, hour=13, minute=18, second=0)+t = datetime(year=2020,​ month=12, day=2, hour=11, minute=18, second=0)
 v.rtc(t) v.rtc(t)
-</​code><​HTML></dd></HTML+</​code><​/pre></div> 
-<HTML><dt></HTML>''​%%rtc_adjust(self, ​val=None)%%''​<HTML></dt></HTML+<details class="​source"​
-<HTML><dd></HTML><HTML><p></HTML>Set or get the real-time clock adjustment. Vizys real-time clock crystal has an accuracy of 20ppm, which means that it can lose or gain up to 20 seconds for every 1 million elapsed seconds. Normally, this isnt an issue, but if Vizy spends a lengthy period of time (months) without Internet access, it could lose or gain minutes, which depending on the application could be significant. The adjustment value can offset this inaccuracy. The ''​%%val%%'' ​argument can range between -128 and 127 and has a multiplier of 2.170 ppm.<​HTML>​</p></​HTML+<summary> 
-<​HTML>​<p></​HTML>For example, if the RTC is gaining 10 seconds every 1 million seconds, you would call ''​%%rtc_adjust(-5)%%''​. If the RTC is losing 10 seconds every million seconds you would call ''​%%rtc_adjust(5)%%''​.<HTML></​p></​HTML+<span>Expand source code</span> 
-<HTML><p></HTML>The adjustment value is retained by the real-time clock even when Vizys power is removed.<​HTML></p></HTML><​HTML></​dd><​/HTML+</​summary>​ 
-<HTML><dt></HTML>''​%%rtc_set_system_datetime(self, datetime_=None)%%''​<HTML></​dt></​HTML+<​pre><​code class="​python">​def rtc(self, ​datetime_=None)
-<HTML><dd></HTML>A convenience method that sets the system time/date based on the real-time time/date. This is called by vizy-powerd upon power-up.<​HTML></dd></HTML+    &#​34;&#​34;&#​34;​ 
-<HTML><​dt><​/HTML>''​%%uuid(self)%%''​<HTML></​dt></​HTML+    Set or get the real-time clock time/​date. ​ The Vizy power board has a  
-<HTML><dd></HTML>Returns a 16-byte unique ID that can be used an a unique ID for your Vizy camera. This unique ID is stored on the Vizy Power Board and remains constant regardless of firmware upgrades, etc.<HTML></dd></HTML+    battery-backed real-time clock that keeps track of time/date, power  
-<HTML><​dt><​/HTML>''​%%vcc12(self, state=None)%%''​<HTML></​dt></​HTML+    alarms, etc. even while Vizy is receiving no power. ​ Passing in a 
-<HTML><dd></HTML>​If ​''​%%state%%'' ​is ''​%%True%%''​, the 12V output on Vizys I/O connector (pin 2) will be enabled and output 12V. If ''​%%state%%'' ​is ''​%%False%%''​, the 12V output will be disabled. Calling without arguments returns its current state.<HTML></dd></HTML+    datetime object sets the time/​date. ​  
-<HTML><​dt><​/HTML>''​%%vcc5(self, state=None)%%''​<HTML></dt></HTML+ 
-<HTML><dd></HTML>​If ​''​%%state%%'' ​is ''​%%True%%''​, the 5V output on Vizys I/O connector (pin 3) will be enabled and output 5V. If ''​%%state%%'' ​is ''​%%False%%''​, the 5V output will be disabled. Calling without arguments returns its current state.<​HTML>​</dd></HTML><HTML></​dl></​HTML+    Calling this method with no 
-<HTML></dd></HTML><HTML></dl></HTML>+    arguments returns a datetime object representing the current  
 +    date/time.  
 + 
 +    For example, the code below sets the date to December 2, 2020, 11:18am: 
 + 
 +        from datetime import datetime 
 +        import vizypowerboard as vpb 
 +        v = vpb.VizyPowerBoard() 
 +        t = datetime(year=2020,​ month=12, day=2, hour=11, minute=18, second=0) 
 +        v.rtc(t) 
 +    &#​34;&#​34;&#​34;​ 
 +    if datetime_ is None: 
 +        # Initiate RTC retrieval. 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC]) 
 +        # Wait until it&#​39;​s ready. 
 +        self._wait_until_not_busy() 
 + 
 +        t = self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 8) 
 +        return datetime.datetime(year=self._bcd2decimal(t[7])+2016,​ month=self._bcd2decimal(t[6]),​ day=self._bcd2decimal(t[4]),​ hour=self._bcd2decimal(t[3]),​ minute=self._bcd2decimal(t[2]),​ second=self._bcd2decimal(t[1])) 
 + 
 +    t = [EXEC_RTC|EXEC_WRITE,​ 0, self._decimal2bcd(datetime_.second),​ self._decimal2bcd(datetime_.minute),​ self._decimal2bcd(datetime_.hour),​ self._decimal2bcd(datetime_.day),​ 0, self._decimal2bcd(datetime_.month),​ self._decimal2bcd(datetime_.year-2016)] 
 +    self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ t) 
 +    self._wait_until_not_busy()</code></pre> 
 +</details
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.rtc_adjust"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident">​rtc_adjust</span></span>(<span>self, val=None)</span> 
 +</​code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>Set or get the real-time clock adjustment. 
 +Vizy's real-time clock 
 +crystal has an accuracy of 20ppm, which means that it can lose or gain 
 +up to 20 seconds for every 1 million elapsed seconds. 
 +Normally, this 
 +isn't an issue, but if Vizy spends a lengthy period of time (months) 
 +without Internet access, it could lose or gain minutes, which 
 +depending on the application could be significant. The adjustment 
 +value can offset this inaccuracy. 
 +The <​code>​val</​code> ​argument can range 
 +between -128 and 127 and has a multiplier of 2.170 ppm. 
 +</​p>​ 
 +<​p>​For example, 
 +if the RTC is gaining 10 seconds every 1 million seconds, you would 
 +call <​code>​rtc_adjust(-5)</​code>​. 
 +If the RTC is losing 10 seconds every million 
 +seconds you would call <​code>​rtc_adjust(5)</​code>​.</p> 
 +<​p>​The adjustment value is retained by the real-time clock even when 
 +Vizy's power is removed.</​p></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def rtc_adjust(self,​ val=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    Set or get the real-time clock adjustment. ​ Vizy&#​39;​s real-time clock  
 +    crystal has an accuracy of 20ppm, which means that it can lose or gain  
 +    up to 20 seconds for every 1 million elapsed seconds. ​ Normally, this 
 +    isn&#​39;​t an issue, but if Vizy spends a lengthy period of time (months) 
 +    without Internet access, it could lose or gain minutes, which  
 +    depending on the application could be significant. The adjustment 
 +    value can offset this inaccuracy. ​ The `val` argument can range  
 +    between -128 and 127 and has a multiplier of 2.170 ppm.   
 + 
 +    For example,  
 +    if the RTC is gaining 10 seconds every 1 million seconds, you would  
 +    call `rtc_adjust(-5)`. ​ If the RTC is losing 10 seconds every million 
 +    seconds you would call `rtc_adjust(5)`. 
 +     
 +    ​The adjustment value is retained by the real-time clock even when  
 +    ​Vizy&#39;s power is removed. ​ 
 +    &#​34;&#​34;&#​34;​ 
 +    if val is None: 
 +        self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC_CALIBRATE]) 
 +        # Wait until it&#​39;​s ready. 
 +        self._wait_until_not_busy() 
 +        return self.bus.read_i2c_block_data(self.addr,​ EXEC_OFFSET+1,​ 1)[0] 
 + 
 +    self.bus.write_i2c_block_data(self.addr,​ EXEC_OFFSET,​ [EXEC_RTC_CALIBRATE|EXEC_WRITE,​ self._int8(val)]) 
 +    self._wait_until_not_busy()</code></pre> 
 +</details> 
 +</dd> 
 +<dt id="​vizypowerboard.VizyPowerBoard.rtc_set_system_datetime"><​code class="​name flex"
 +<span>def <span class="​ident"​>rtc_set_system_datetime</span></​span>(<​span>​self, datetime_=None)<​/span> 
 +</code></​dt>​ 
 +<dd> 
 +<div class="​desc"><​p>​A convenience method that sets the system time/date based on the 
 +real-time time/​date. 
 +This is called by vizy-powerd upon power-up.</​p></​div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def rtc_set_system_datetime(self,​ datetime_=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    ​A convenience method that sets the system time/date based on the  
 +    ​real-time time/​date. ​ This is called by vizy-powerd upon power-up. ​ 
 +    &#​34;&#​34;&#​34;​ 
 +    if os.geteuid()!=0:​ 
 +        raise PermissionError(&#​34;​You need root permission to set the time/​date.&#​34;​) 
 +    if datetime_ is None: 
 +        datetime_ = self.rtc() 
 +    s = datetime_.isoformat() 
 +    os.system(f&#​34;​sudo date -s {s}&#​34;​)</code></pre> 
 +</details
 +</dd> 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.uuid"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>uuid</​span></​span>​(<​span>​self)</span> 
 +</code></dt
 +<​dd>​ 
 +<div class="​desc"><​p>​Returns a 16-byte unique ID that can be used an a unique 
 +ID for your Vizy camera. 
 +This unique ID is stored on the Vizy Power 
 +Board and remains constant regardless of firmware upgrades, etc.</p></div
 +<details class="​source"​> 
 +<summary> 
 +<​span>​Expand source code</span> 
 +</​summary>​ 
 +<​pre><​code class="​python">​def uuid(self):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    ​Returns a 16-byte unique ID that can be used an a unique 
 +    ​ID for your Vizy camera. ​ This unique ID is stored on the Vizy Power 
 +    ​Board and remains constant regardless of firmware upgrades, etc. 
 +    &#​34;&#​34;&#​34;​ 
 +    return self.bus.read_i2c_block_data(self.addr,​ 22, 16)</code></pre> 
 +</details
 +</dd> 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.vcc12"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>vcc12</​span></​span>​(<​span>​self, state=None)<​/span> 
 +</code></​dt>​ 
 +<​dd>​ 
 +<div class="​desc"><​p>​If <​code>​state</codeis <​code>​True</​code>,​ the 12V output on Vizy's I/O connector (pin 2) will be enabled and output 12V. 
 +If <code>state</codeis <​code>​False</code>, the 12V output 
 +will be disabled. 
 +Calling without arguments returns its current state.</​p></​div>​ 
 +<details class="​source">​ 
 +<​summary>​ 
 +<​span>​Expand source code</​span>​ 
 +</​summary>​ 
 +<​pre><​code class="​python">​def vcc12(self, state=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    ​If `stateis `True`, the 12V output on Vizy&#39;s I/O connector (pin 2) will be enabled and output 12V.  If `stateis `False`, the 12V output 
 +    ​will be disabled. ​ Calling without arguments returns its current state. 
 +    &#​34;&#​34;&#​34;​  
 +    config = self.bus.read_i2c_block_data(self.addr,​ 48, 1) 
 +    if state is None: 
 +        return True if config&​amp;​0x01 else False 
 +    if state: 
 +        config[0] |= 0x01 
 +    else: 
 +        config[0] &amp;= ~0x01 
 + 
 +    self.bus.write_i2c_block_data(self.addr,​ 48, config)</code></pre> 
 +</details
 +</dd> 
 +<​dt ​id="​vizypowerboard.VizyPowerBoard.vcc5"​><code class="​name flex">​ 
 +<​span>​def <span class="​ident"​>vcc5</​span></​span>​(<​span>​self, state=None)<​/span> 
 +</code></dt
 +<dd> 
 +<div class="​desc"​><p>​If ​<​code>​state</​code> ​is <​code>​True</​code>​, the 5V output on Vizy's I/O connector (pin 3) will 
 +be enabled and output 5V. 
 +If <​code>​state</​code> ​is <​code>​False</​code>​, the 5V output will be 
 +disabled. 
 +Calling without arguments returns its current state.</p></div> 
 +<details class="​source"​> 
 +<summary
 +<span>Expand source code</span> 
 +</summary> 
 +<pre><code class="​python"​>def vcc5(self, state=None):​ 
 +    &#​34;&#​34;&#​34;​ 
 +    If `state` is `True`, the 5V output on Vizy&#​39;​s I/O connector (pin 3) will 
 +    be enabled and output 5V.  If `state` is `False`, the 5V output will be 
 +    disabled. ​ Calling without arguments returns its current state. 
 +    &#​34;&#​34;&#​34;​  
 +    if state is None: 
 +        return True if config&​amp;​0x02 else False 
 +    if state: 
 +        config[0] |= 0x02 
 +    else: 
 +        config[0] &amp;= ~0x02
  
 +    self.bus.write_i2c_block_data(self.addr,​ 48, config)</​code></​pre>​
 +</​details>​
 +</dd>
 +</dl>
 +</dd>
 +</dl>
 +</​section>​
 +</​article>​
 +<nav id="​sidebar">​
 +<​h1>​Index</​h1>​
 +<div class="​toc">​
 +<​ul></​ul>​
 +</​div>​
 +<ul id="​index">​
 +<​li><​h3><​a href="#​header-variables">​Global variables</​a></​h3>​
 +<ul class="">​
 +<​li><​code><​a title="​vizypowerboard.CHANNEL_5V"​ href="#​vizypowerboard.CHANNEL_5V">​CHANNEL_5V</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.CHANNEL_VIN"​ href="#​vizypowerboard.CHANNEL_VIN">​CHANNEL_VIN</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.DIPSWITCH_EXT_BUTTON"​ href="#​vizypowerboard.DIPSWITCH_EXT_BUTTON">​DIPSWITCH_EXT_BUTTON</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.DIPSWITCH_MUTE_BUZZER"​ href="#​vizypowerboard.DIPSWITCH_MUTE_BUZZER">​DIPSWITCH_MUTE_BUZZER</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.DIPSWITCH_NO_BG_LED"​ href="#​vizypowerboard.DIPSWITCH_NO_BG_LED">​DIPSWITCH_NO_BG_LED</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.DIPSWITCH_POWER_DEFAULT_OFF"​ href="#​vizypowerboard.DIPSWITCH_POWER_DEFAULT_OFF">​DIPSWITCH_POWER_DEFAULT_OFF</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.DIPSWITCH_POWER_DEFAULT_ON"​ href="#​vizypowerboard.DIPSWITCH_POWER_DEFAULT_ON">​DIPSWITCH_POWER_DEFAULT_ON</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.DIPSWITCH_POWER_PLUG"​ href="#​vizypowerboard.DIPSWITCH_POWER_PLUG">​DIPSWITCH_POWER_PLUG</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.DIPSWITCH_POWER_SWITCH"​ href="#​vizypowerboard.DIPSWITCH_POWER_SWITCH">​DIPSWITCH_POWER_SWITCH</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.IO_MODE_HIGH_CURRENT"​ href="#​vizypowerboard.IO_MODE_HIGH_CURRENT">​IO_MODE_HIGH_CURRENT</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.IO_MODE_INPUT"​ href="#​vizypowerboard.IO_MODE_INPUT">​IO_MODE_INPUT</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.IO_MODE_OUTPUT"​ href="#​vizypowerboard.IO_MODE_OUTPUT">​IO_MODE_OUTPUT</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.POWER_ON_SOURCE_12V"​ href="#​vizypowerboard.POWER_ON_SOURCE_12V">​POWER_ON_SOURCE_12V</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.POWER_ON_SOURCE_5V"​ href="#​vizypowerboard.POWER_ON_SOURCE_5V">​POWER_ON_SOURCE_5V</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.POWER_ON_SOURCE_ALARM"​ href="#​vizypowerboard.POWER_ON_SOURCE_ALARM">​POWER_ON_SOURCE_ALARM</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.POWER_ON_SOURCE_POWER_BUTTON"​ href="#​vizypowerboard.POWER_ON_SOURCE_POWER_BUTTON">​POWER_ON_SOURCE_POWER_BUTTON</​a></​code></​li>​
 +</ul>
 +</li>
 +<​li><​h3><​a href="#​header-classes">​Classes</​a></​h3>​
 +<ul>
 +<li>
 +<​h4><​code><​a title="​vizypowerboard.VizyPowerBoard"​ href="#​vizypowerboard.VizyPowerBoard">​VizyPowerBoard</​a></​code></​h4>​
 +<ul class="">​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.button"​ href="#​vizypowerboard.VizyPowerBoard.button">​button</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.button_pressed"​ href="#​vizypowerboard.VizyPowerBoard.button_pressed">​button_pressed</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.buzzer"​ href="#​vizypowerboard.VizyPowerBoard.buzzer">​buzzer</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.dip_switches"​ href="#​vizypowerboard.VizyPowerBoard.dip_switches">​dip_switches</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.fan"​ href="#​vizypowerboard.VizyPowerBoard.fan">​fan</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.fw_version"​ href="#​vizypowerboard.VizyPowerBoard.fw_version">​fw_version</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.hw_version"​ href="#​vizypowerboard.VizyPowerBoard.hw_version">​hw_version</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.io_bits"​ href="#​vizypowerboard.VizyPowerBoard.io_bits">​io_bits</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.io_set_mode"​ href="#​vizypowerboard.VizyPowerBoard.io_set_mode">​io_set_mode</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.ir_filter"​ href="#​vizypowerboard.VizyPowerBoard.ir_filter">​ir_filter</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.led"​ href="#​vizypowerboard.VizyPowerBoard.led">​led</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.led_background"​ href="#​vizypowerboard.VizyPowerBoard.led_background">​led_background</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.led_unicorn"​ href="#​vizypowerboard.VizyPowerBoard.led_unicorn">​led_unicorn</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.measure"​ href="#​vizypowerboard.VizyPowerBoard.measure">​measure</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.power_off"​ href="#​vizypowerboard.VizyPowerBoard.power_off">​power_off</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.power_off_requested"​ href="#​vizypowerboard.VizyPowerBoard.power_off_requested">​power_off_requested</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.power_on_alarm_date"​ href="#​vizypowerboard.VizyPowerBoard.power_on_alarm_date">​power_on_alarm_date</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.power_on_alarm_seconds"​ href="#​vizypowerboard.VizyPowerBoard.power_on_alarm_seconds">​power_on_alarm_seconds</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.power_on_source"​ href="#​vizypowerboard.VizyPowerBoard.power_on_source">​power_on_source</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.resource_url"​ href="#​vizypowerboard.VizyPowerBoard.resource_url">​resource_url</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.rtc"​ href="#​vizypowerboard.VizyPowerBoard.rtc">​rtc</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.rtc_adjust"​ href="#​vizypowerboard.VizyPowerBoard.rtc_adjust">​rtc_adjust</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.rtc_set_system_datetime"​ href="#​vizypowerboard.VizyPowerBoard.rtc_set_system_datetime">​rtc_set_system_datetime</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.uuid"​ href="#​vizypowerboard.VizyPowerBoard.uuid">​uuid</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.vcc12"​ href="#​vizypowerboard.VizyPowerBoard.vcc12">​vcc12</​a></​code></​li>​
 +<​li><​code><​a title="​vizypowerboard.VizyPowerBoard.vcc5"​ href="#​vizypowerboard.VizyPowerBoard.vcc5">​vcc5</​a></​code></​li>​
 +</ul>
 +</li>
 +</ul>
 +</li>
 +</ul>
 +</​nav>​
 +</​main>​
 +<footer id="​footer">​
 +<​p>​Generated by <a href="​https://​pdoc3.github.io/​pdoc"><​cite>​pdoc</​cite>​ 0.9.2</​a>​.</​p>​
 +</​footer>​
 +</​body>​
 +</​html>​
 +</​HTML>​
  
wiki/test.1613244086.txt.gz · Last modified: 2021/02/13 13:21 by vizycam