mirror of
https://github.com/okunze/Argon40-ArgonOne-Script.git
synced 2025-06-30 00:37:30 +02:00
Automated Change by GitHub Action
This commit is contained in:
committed by
github-actions[bot]
parent
1a7ab2e005
commit
755a2ca262
Binary file not shown.
Before Width: | Height: | Size: 118 KiB |
BIN
source/argoneon.png
Normal file
BIN
source/argoneon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
source/oled/bgcpu.bin
Normal file
BIN
source/oled/bgcpu.bin
Normal file
Binary file not shown.
BIN
source/oled/bgdefault.bin
Normal file
BIN
source/oled/bgdefault.bin
Normal file
Binary file not shown.
BIN
source/oled/bgip.bin
Normal file
BIN
source/oled/bgip.bin
Normal file
Binary file not shown.
BIN
source/oled/bgraid.bin
Normal file
BIN
source/oled/bgraid.bin
Normal file
Binary file not shown.
BIN
source/oled/bgram.bin
Normal file
BIN
source/oled/bgram.bin
Normal file
Binary file not shown.
BIN
source/oled/bgstorage.bin
Normal file
BIN
source/oled/bgstorage.bin
Normal file
Binary file not shown.
BIN
source/oled/bgtemp.bin
Normal file
BIN
source/oled/bgtemp.bin
Normal file
Binary file not shown.
BIN
source/oled/bgtime.bin
Normal file
BIN
source/oled/bgtime.bin
Normal file
Binary file not shown.
BIN
source/oled/font16x12.bin
Normal file
BIN
source/oled/font16x12.bin
Normal file
Binary file not shown.
BIN
source/oled/font16x8.bin
Normal file
BIN
source/oled/font16x8.bin
Normal file
Binary file not shown.
BIN
source/oled/font24x16.bin
Normal file
BIN
source/oled/font24x16.bin
Normal file
Binary file not shown.
BIN
source/oled/font32x24.bin
Normal file
BIN
source/oled/font32x24.bin
Normal file
Binary file not shown.
BIN
source/oled/font48x32.bin
Normal file
BIN
source/oled/font48x32.bin
Normal file
Binary file not shown.
BIN
source/oled/font64x48.bin
Normal file
BIN
source/oled/font64x48.bin
Normal file
Binary file not shown.
BIN
source/oled/font8x6.bin
Normal file
BIN
source/oled/font8x6.bin
Normal file
Binary file not shown.
BIN
source/oled/logo1v5.bin
Normal file
BIN
source/oled/logo1v5.bin
Normal file
Binary file not shown.
194
source/scripts/argon-blstrdac.sh
Normal file
194
source/scripts/argon-blstrdac.sh
Normal file
@ -0,0 +1,194 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
if [ -e /boot/firmware/config.txt ] ; then
|
||||
FIRMWARE=/firmware
|
||||
else
|
||||
FIRMWARE=
|
||||
fi
|
||||
CONFIG=/boot${FIRMWARE}/config.txt
|
||||
|
||||
# Check if Raspbian
|
||||
CHECKPLATFORM="Others"
|
||||
if [ -f "/etc/os-release" ]
|
||||
then
|
||||
source /etc/os-release
|
||||
if [ "$ID" = "raspbian" ]
|
||||
then
|
||||
CHECKPLATFORM="Raspbian"
|
||||
elif [ "$ID" = "debian" ]
|
||||
then
|
||||
# For backwards compatibility, continue using raspbian
|
||||
CHECKPLATFORM="Raspbian"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
echo "------------------------------------"
|
||||
echo " Argon BLSTR DAC Configuration Tool"
|
||||
echo "------------------------------------"
|
||||
|
||||
get_number () {
|
||||
read curnumber
|
||||
if [ -z "$curnumber" ]
|
||||
then
|
||||
echo "-2"
|
||||
return
|
||||
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||
then
|
||||
if [ $curnumber -lt 0 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
elif [ $curnumber -gt 100 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
fi
|
||||
echo $curnumber
|
||||
return
|
||||
fi
|
||||
echo "-1"
|
||||
return
|
||||
}
|
||||
|
||||
irexecrcfile=/etc/lirc/irexec.lircrc
|
||||
irexecshfile=/etc/argon/argonirexec
|
||||
irdecodefile=/etc/argon/argonirdecoder
|
||||
kodiuserdatafolder="$HOME/.kodi/userdata"
|
||||
kodilircmapfile="$kodiuserdatafolder/Lircmap.xml"
|
||||
remotemode=""
|
||||
needinstallation=1
|
||||
|
||||
|
||||
CONFIGSETTING="dtoverlay=hifiberry-dacplus,slave"
|
||||
|
||||
if grep -q -E "$CONFIGSETTING" $CONFIG
|
||||
then
|
||||
# Already installed
|
||||
needinstallation=0
|
||||
fi
|
||||
|
||||
|
||||
loopflag=1
|
||||
while [ $loopflag -eq 1 ]
|
||||
do
|
||||
echo
|
||||
echo "Select option:"
|
||||
if [ $needinstallation -eq 1 ]
|
||||
then
|
||||
echo " 1. Enable BLSTR DAC"
|
||||
echo " 2. Cancel"
|
||||
echo -n "Enter Number (1-2):"
|
||||
else
|
||||
echo " 1. Select audio configuration"
|
||||
echo " 2. Disable BLSTR DAC"
|
||||
echo " 3. Cancel"
|
||||
echo -n "Enter Number (1-3):"
|
||||
fi
|
||||
newmode=$( get_number )
|
||||
if [[ $newmode -ge 1 && $newmode -le 3 ]]
|
||||
then
|
||||
if [[ $needinstallation -eq 1 && $newmode -ge 3 ]]
|
||||
then
|
||||
# Invalid option
|
||||
loopflag=1
|
||||
# Uninstall
|
||||
else
|
||||
loopflag=0
|
||||
if [ $needinstallation -eq 1 ]
|
||||
then
|
||||
if [ $newmode -eq 2 ]
|
||||
then
|
||||
# Cancel
|
||||
newmode=4
|
||||
fi
|
||||
else
|
||||
if [ $newmode -eq 1 ]
|
||||
then
|
||||
# Audio Conf
|
||||
newmode=3
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
needrestart=0
|
||||
|
||||
echo
|
||||
if [ $newmode -eq 2 ]
|
||||
then
|
||||
# Uninstall
|
||||
blstrdactmpconfigfile=/dev/shm/argonblstrdacconfig.txt
|
||||
|
||||
cat $CONFIG | grep -v "$CONFIGSETTING" > $blstrdactmpconfigfile
|
||||
cat $blstrdactmpconfigfile | sudo tee $CONFIG 1> /dev/null
|
||||
sudo rm $blstrdactmpconfigfile
|
||||
|
||||
echo "Uninstall Completed"
|
||||
echo
|
||||
|
||||
needrestart=1
|
||||
|
||||
elif [ $newmode -eq 3 ]
|
||||
then
|
||||
# Audio Conf
|
||||
|
||||
loopflag=1
|
||||
while [ $loopflag -eq 1 ]
|
||||
do
|
||||
echo
|
||||
echo "Select audio configuration:"
|
||||
echo " 1. PulseAudio"
|
||||
echo " 2. Pipewire"
|
||||
echo " 3. Cancel"
|
||||
echo -n "Enter Number (1-3):"
|
||||
|
||||
newmode=$( get_number )
|
||||
if [[ $newmode -ge 1 && $newmode -le 3 ]]
|
||||
then
|
||||
loopflag=0
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $newmode -ge 1 && $newmode -le 2 ]]
|
||||
then
|
||||
sudo raspi-config nonint do_audioconf $newmode
|
||||
else
|
||||
echo "Cancelled"
|
||||
fi
|
||||
|
||||
elif [ $newmode -eq 1 ]
|
||||
then
|
||||
# Install
|
||||
|
||||
echo "$CONFIGSETTING" | sudo tee -a $CONFIG 1> /dev/null
|
||||
|
||||
#sudo raspi-config nonint do_audioconf 1
|
||||
#systemctl --global -q disable pipewire-pulse
|
||||
#systemctl --global -q disable wireplumber
|
||||
#systemctl --global -q enable pulseaudio
|
||||
#if [ -e /etc/alsa/conf.d/99-pipewire-default.conf ] ; then
|
||||
# rm /etc/alsa/conf.d/99-pipewire-default.conf
|
||||
#fi
|
||||
|
||||
echo "Please run configuration and choose different audio configuration if there are problems"
|
||||
|
||||
needrestart=1
|
||||
else
|
||||
echo "Cancelled"
|
||||
#exit
|
||||
fi
|
||||
|
||||
|
||||
echo
|
||||
#echo "Thank you."
|
||||
if [ $needrestart -eq 1 ]
|
||||
then
|
||||
echo "Changes should take after reboot."
|
||||
fi
|
||||
|
568
source/scripts/argon-rpi-eeprom-config-psu.py
Normal file
568
source/scripts/argon-rpi-eeprom-config-psu.py
Normal file
@ -0,0 +1,568 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Based on /usr/bin/rpi-eeprom-config of bookworm
|
||||
"""
|
||||
rpi-eeprom-config
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import atexit
|
||||
import os
|
||||
import subprocess
|
||||
import string
|
||||
import struct
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
VALID_IMAGE_SIZES = [512 * 1024, 2 * 1024 * 1024]
|
||||
|
||||
BOOTCONF_TXT = 'bootconf.txt'
|
||||
BOOTCONF_SIG = 'bootconf.sig'
|
||||
PUBKEY_BIN = 'pubkey.bin'
|
||||
|
||||
# Each section starts with a magic number followed by a 32 bit offset to the
|
||||
# next section (big-endian).
|
||||
# The number, order and size of the sections depends on the bootloader version
|
||||
# but the following mask can be used to test for section headers and skip
|
||||
# unknown data.
|
||||
#
|
||||
# The last 4KB of the EEPROM image is reserved for internal use by the
|
||||
# bootloader and may be overwritten during the update process.
|
||||
MAGIC = 0x55aaf00f
|
||||
PAD_MAGIC = 0x55aafeef
|
||||
MAGIC_MASK = 0xfffff00f
|
||||
FILE_MAGIC = 0x55aaf11f # id for modifiable files
|
||||
FILE_HDR_LEN = 20
|
||||
FILENAME_LEN = 12
|
||||
TEMP_DIR = None
|
||||
|
||||
# Modifiable files are stored in a single 4K erasable sector.
|
||||
# The max content 4076 bytes because of the file header.
|
||||
ERASE_ALIGN_SIZE = 4096
|
||||
MAX_FILE_SIZE = ERASE_ALIGN_SIZE - FILE_HDR_LEN
|
||||
|
||||
DEBUG = False
|
||||
|
||||
# BEGIN: Argon40 added methods
|
||||
def argon_rpisupported():
|
||||
# bcm2711 = pi4, bcm2712 = pi5
|
||||
return rpi5()
|
||||
|
||||
def argon_edit_config():
|
||||
# modified/stripped version of edit_config
|
||||
|
||||
config_src = ''
|
||||
# If there is a pending update then use the configuration from
|
||||
# that in order to support incremental updates. Otherwise,
|
||||
# use the current EEPROM configuration.
|
||||
bootfs = shell_cmd(['rpi-eeprom-update', '-b']).rstrip()
|
||||
pending = os.path.join(bootfs, 'pieeprom.upd')
|
||||
if os.path.exists(pending):
|
||||
config_src = pending
|
||||
image = BootloaderImage(pending)
|
||||
current_config = image.get_file(BOOTCONF_TXT).decode('utf-8')
|
||||
else:
|
||||
current_config, config_src = read_current_config()
|
||||
|
||||
# Add PSU Mas Current etc if not yet set
|
||||
foundnewsetting = 0
|
||||
addsetting="\nPSU_MAX_CURRENT=5000"
|
||||
current_config_lines = current_config.splitlines()
|
||||
new_config = current_config
|
||||
lineidx = 0
|
||||
while lineidx < len(current_config_lines):
|
||||
current_config_pair = current_config_lines[lineidx].split("=")
|
||||
newsetting = ""
|
||||
if current_config_pair[0] == "PSU_MAX_CURRENT":
|
||||
newsetting = "PSU_MAX_CURRENT=5000"
|
||||
|
||||
if newsetting != "":
|
||||
addsetting = addsetting.replace("\n"+newsetting,"",1)
|
||||
if current_config_lines[lineidx] != newsetting:
|
||||
foundnewsetting = foundnewsetting + 1
|
||||
new_config = new_config.replace(current_config_lines[lineidx], newsetting, 1)
|
||||
|
||||
lineidx = lineidx + 1
|
||||
|
||||
if addsetting != "":
|
||||
# Append additional settings after [all]
|
||||
new_config = new_config.replace("[all]", "[all]"+addsetting, 1)
|
||||
foundnewsetting = foundnewsetting + 1
|
||||
|
||||
if foundnewsetting == 0:
|
||||
# Already configured
|
||||
print("EEPROM settings up to date")
|
||||
sys.exit(0)
|
||||
|
||||
# Skipped editor and write new config to temp file
|
||||
create_tempdir()
|
||||
tmp_conf = os.path.join(TEMP_DIR, 'boot.conf')
|
||||
out = open(tmp_conf, 'w')
|
||||
out.write(new_config)
|
||||
out.close()
|
||||
|
||||
# Apply updates
|
||||
|
||||
apply_update(tmp_conf, None, config_src)
|
||||
|
||||
# END: Argon40 added methods
|
||||
|
||||
|
||||
def debug(s):
|
||||
if DEBUG:
|
||||
sys.stderr.write(s + '\n')
|
||||
|
||||
|
||||
def rpi4():
|
||||
compatible_path = "/sys/firmware/devicetree/base/compatible"
|
||||
if os.path.exists(compatible_path):
|
||||
with open(compatible_path, "rb") as f:
|
||||
compatible = f.read().decode('utf-8')
|
||||
if "bcm2711" in compatible:
|
||||
return True
|
||||
return False
|
||||
|
||||
def rpi5():
|
||||
compatible_path = "/sys/firmware/devicetree/base/compatible"
|
||||
if os.path.exists(compatible_path):
|
||||
with open(compatible_path, "rb") as f:
|
||||
compatible = f.read().decode('utf-8')
|
||||
if "bcm2712" in compatible:
|
||||
return True
|
||||
return False
|
||||
|
||||
def exit_handler():
|
||||
"""
|
||||
Delete any temporary files.
|
||||
"""
|
||||
if TEMP_DIR is not None and os.path.exists(TEMP_DIR):
|
||||
tmp_image = os.path.join(TEMP_DIR, 'pieeprom.upd')
|
||||
if os.path.exists(tmp_image):
|
||||
os.remove(tmp_image)
|
||||
tmp_conf = os.path.join(TEMP_DIR, 'boot.conf')
|
||||
if os.path.exists(tmp_conf):
|
||||
os.remove(tmp_conf)
|
||||
os.rmdir(TEMP_DIR)
|
||||
|
||||
def create_tempdir():
|
||||
global TEMP_DIR
|
||||
if TEMP_DIR is None:
|
||||
TEMP_DIR = tempfile.mkdtemp()
|
||||
|
||||
def pemtobin(infile):
|
||||
"""
|
||||
Converts an RSA public key into the format expected by the bootloader.
|
||||
"""
|
||||
# Import the package here to make this a weak dependency.
|
||||
from Cryptodome.PublicKey import RSA
|
||||
|
||||
arr = bytearray()
|
||||
f = open(infile,'r')
|
||||
key = RSA.importKey(f.read())
|
||||
|
||||
if key.size_in_bits() != 2048:
|
||||
raise Exception("RSA key size must be 2048")
|
||||
|
||||
# Export N and E in little endian format
|
||||
arr.extend(key.n.to_bytes(256, byteorder='little'))
|
||||
arr.extend(key.e.to_bytes(8, byteorder='little'))
|
||||
return arr
|
||||
|
||||
def exit_error(msg):
|
||||
"""
|
||||
Trapped a fatal error, output message to stderr and exit with non-zero
|
||||
return code.
|
||||
"""
|
||||
sys.stderr.write("ERROR: %s\n" % msg)
|
||||
sys.exit(1)
|
||||
|
||||
def shell_cmd(args):
|
||||
"""
|
||||
Executes a shell command waits for completion returning STDOUT. If an
|
||||
error occurs then exit and output the subprocess stdout, stderr messages
|
||||
for debug.
|
||||
"""
|
||||
start = time.time()
|
||||
arg_str = ' '.join(args)
|
||||
result = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
while time.time() - start < 5:
|
||||
if result.poll() is not None:
|
||||
break
|
||||
|
||||
if result.poll() is None:
|
||||
exit_error("%s timeout" % arg_str)
|
||||
|
||||
if result.returncode != 0:
|
||||
exit_error("%s failed: %d\n %s\n %s\n" %
|
||||
(arg_str, result.returncode, result.stdout.read(), result.stderr.read()))
|
||||
else:
|
||||
return result.stdout.read().decode('utf-8')
|
||||
|
||||
def get_latest_eeprom():
|
||||
"""
|
||||
Returns the path of the latest EEPROM image file if it exists.
|
||||
"""
|
||||
latest = shell_cmd(['rpi-eeprom-update', '-l']).rstrip()
|
||||
if not os.path.exists(latest):
|
||||
exit_error("EEPROM image '%s' not found" % latest)
|
||||
return latest
|
||||
|
||||
def apply_update(config, eeprom=None, config_src=None):
|
||||
"""
|
||||
Applies the config file to the latest available EEPROM image and spawns
|
||||
rpi-eeprom-update to schedule the update at the next reboot.
|
||||
"""
|
||||
if eeprom is not None:
|
||||
eeprom_image = eeprom
|
||||
else:
|
||||
eeprom_image = get_latest_eeprom()
|
||||
create_tempdir()
|
||||
|
||||
# Replace the contents of bootconf.txt with the contents of the config file
|
||||
tmp_update = os.path.join(TEMP_DIR, 'pieeprom.upd')
|
||||
image = BootloaderImage(eeprom_image, tmp_update)
|
||||
image.update_file(config, BOOTCONF_TXT)
|
||||
image.write()
|
||||
|
||||
config_str = open(config).read()
|
||||
if config_src is None:
|
||||
config_src = ''
|
||||
sys.stdout.write("Updating bootloader EEPROM\n image: %s\nconfig_src: %s\nconfig: %s\n%s\n%s\n%s\n" %
|
||||
(eeprom_image, config_src, config, '#' * 80, config_str, '#' * 80))
|
||||
|
||||
sys.stdout.write("\n*** To cancel this update run 'sudo rpi-eeprom-update -r' ***\n\n")
|
||||
|
||||
# Ignore APT package checksums so that this doesn't fail when used
|
||||
# with EEPROMs with configs delivered outside of APT.
|
||||
# The checksums are really just a safety check for automatic updates.
|
||||
args = ['rpi-eeprom-update', '-d', '-i', '-f', tmp_update]
|
||||
resp = shell_cmd(args)
|
||||
sys.stdout.write(resp)
|
||||
|
||||
def edit_config(eeprom=None):
|
||||
"""
|
||||
Implements something like 'git commit' for editing EEPROM configs.
|
||||
"""
|
||||
# Default to nano if $EDITOR is not defined.
|
||||
editor = 'nano'
|
||||
if 'EDITOR' in os.environ:
|
||||
editor = os.environ['EDITOR']
|
||||
|
||||
config_src = ''
|
||||
# If there is a pending update then use the configuration from
|
||||
# that in order to support incremental updates. Otherwise,
|
||||
# use the current EEPROM configuration.
|
||||
bootfs = shell_cmd(['rpi-eeprom-update', '-b']).rstrip()
|
||||
pending = os.path.join(bootfs, 'pieeprom.upd')
|
||||
if os.path.exists(pending):
|
||||
config_src = pending
|
||||
image = BootloaderImage(pending)
|
||||
current_config = image.get_file(BOOTCONF_TXT).decode('utf-8')
|
||||
else:
|
||||
current_config, config_src = read_current_config()
|
||||
|
||||
create_tempdir()
|
||||
tmp_conf = os.path.join(TEMP_DIR, 'boot.conf')
|
||||
out = open(tmp_conf, 'w')
|
||||
out.write(current_config)
|
||||
out.close()
|
||||
cmd = "\'%s\' \'%s\'" % (editor, tmp_conf)
|
||||
result = os.system(cmd)
|
||||
if result != 0:
|
||||
exit_error("Aborting update because \'%s\' exited with code %d." % (cmd, result))
|
||||
|
||||
new_config = open(tmp_conf, 'r').read()
|
||||
if len(new_config.splitlines()) < 2:
|
||||
exit_error("Aborting update because \'%s\' appears to be empty." % tmp_conf)
|
||||
apply_update(tmp_conf, eeprom, config_src)
|
||||
|
||||
def read_current_config():
|
||||
"""
|
||||
Reads the configuration used by the current bootloader.
|
||||
"""
|
||||
fw_base = "/sys/firmware/devicetree/base/"
|
||||
nvmem_base = "/sys/bus/nvmem/devices/"
|
||||
|
||||
if os.path.exists(fw_base + "/aliases/blconfig"):
|
||||
with open(fw_base + "/aliases/blconfig", "rb") as f:
|
||||
nvmem_ofnode_path = fw_base + f.read().decode('utf-8')
|
||||
for d in os.listdir(nvmem_base):
|
||||
if os.path.realpath(nvmem_base + d + "/of_node") in os.path.normpath(nvmem_ofnode_path):
|
||||
return (open(nvmem_base + d + "/nvmem", "rb").read().decode('utf-8'), "blconfig device")
|
||||
|
||||
return (shell_cmd(['vcgencmd', 'bootloader_config']), "vcgencmd bootloader_config")
|
||||
|
||||
class ImageSection:
|
||||
def __init__(self, magic, offset, length, filename=''):
|
||||
self.magic = magic
|
||||
self.offset = offset
|
||||
self.length = length
|
||||
self.filename = filename
|
||||
debug("ImageSection %x offset %d length %d %s" % (magic, offset, length, filename))
|
||||
|
||||
class BootloaderImage(object):
|
||||
def __init__(self, filename, output=None):
|
||||
"""
|
||||
Instantiates a Bootloader image writer with a source eeprom (filename)
|
||||
and optionally an output filename.
|
||||
"""
|
||||
self._filename = filename
|
||||
self._sections = []
|
||||
self._image_size = 0
|
||||
try:
|
||||
self._bytes = bytearray(open(filename, 'rb').read())
|
||||
except IOError as err:
|
||||
exit_error("Failed to read \'%s\'\n%s\n" % (filename, str(err)))
|
||||
self._out = None
|
||||
if output is not None:
|
||||
self._out = open(output, 'wb')
|
||||
|
||||
self._image_size = len(self._bytes)
|
||||
if self._image_size not in VALID_IMAGE_SIZES:
|
||||
exit_error("%s: Expected size %d bytes actual size %d bytes" %
|
||||
(filename, self._image_size, len(self._bytes)))
|
||||
self.parse()
|
||||
|
||||
def parse(self):
|
||||
"""
|
||||
Builds a table of offsets to the different sections in the EEPROM.
|
||||
"""
|
||||
offset = 0
|
||||
magic = 0
|
||||
while offset < self._image_size:
|
||||
magic, length = struct.unpack_from('>LL', self._bytes, offset)
|
||||
if magic == 0x0 or magic == 0xffffffff:
|
||||
break # EOF
|
||||
elif (magic & MAGIC_MASK) != MAGIC:
|
||||
raise Exception('EEPROM is corrupted %x %x %x' % (magic, magic & MAGIC_MASK, MAGIC))
|
||||
|
||||
filename = ''
|
||||
if magic == FILE_MAGIC: # Found a file
|
||||
# Discard trailing null characters used to pad filename
|
||||
filename = self._bytes[offset + 8: offset + FILE_HDR_LEN].decode('utf-8').replace('\0', '')
|
||||
debug("section at %d length %d magic %08x %s" % (offset, length, magic, filename))
|
||||
self._sections.append(ImageSection(magic, offset, length, filename))
|
||||
|
||||
offset += 8 + length # length + type
|
||||
offset = (offset + 7) & ~7
|
||||
|
||||
def find_file(self, filename):
|
||||
"""
|
||||
Returns the offset, length and whether this is the last section in the
|
||||
EEPROM for a modifiable file within the image.
|
||||
"""
|
||||
offset = -1
|
||||
length = -1
|
||||
is_last = False
|
||||
|
||||
next_offset = self._image_size - ERASE_ALIGN_SIZE # Don't create padding inside the bootloader scratch page
|
||||
for i in range(0, len(self._sections)):
|
||||
s = self._sections[i]
|
||||
if s.magic == FILE_MAGIC and s.filename == filename:
|
||||
is_last = (i == len(self._sections) - 1)
|
||||
offset = s.offset
|
||||
length = s.length
|
||||
break
|
||||
|
||||
# Find the start of the next non padding section
|
||||
i += 1
|
||||
while i < len(self._sections):
|
||||
if self._sections[i].magic == PAD_MAGIC:
|
||||
i += 1
|
||||
else:
|
||||
next_offset = self._sections[i].offset
|
||||
break
|
||||
ret = (offset, length, is_last, next_offset)
|
||||
debug('%s offset %d length %d is-last %d next %d' % (filename, ret[0], ret[1], ret[2], ret[3]))
|
||||
return ret
|
||||
|
||||
def update(self, src_bytes, dst_filename):
|
||||
"""
|
||||
Replaces a modifiable file with specified byte array.
|
||||
"""
|
||||
hdr_offset, length, is_last, next_offset = self.find_file(dst_filename)
|
||||
update_len = len(src_bytes) + FILE_HDR_LEN
|
||||
|
||||
if hdr_offset + update_len > self._image_size - ERASE_ALIGN_SIZE:
|
||||
raise Exception('No space available - image past EOF.')
|
||||
|
||||
if hdr_offset < 0:
|
||||
raise Exception('Update target %s not found' % dst_filename)
|
||||
|
||||
if hdr_offset + update_len > next_offset:
|
||||
raise Exception('Update %d bytes is larger than section size %d' % (update_len, next_offset - hdr_offset))
|
||||
|
||||
new_len = len(src_bytes) + FILENAME_LEN + 4
|
||||
struct.pack_into('>L', self._bytes, hdr_offset + 4, new_len)
|
||||
struct.pack_into(("%ds" % len(src_bytes)), self._bytes,
|
||||
hdr_offset + 4 + FILE_HDR_LEN, src_bytes)
|
||||
|
||||
# If the new file is smaller than the old file then set any old
|
||||
# data which is now unused to all ones (erase value)
|
||||
pad_start = hdr_offset + 4 + FILE_HDR_LEN + len(src_bytes)
|
||||
|
||||
# Add padding up to 8-byte boundary
|
||||
while pad_start % 8 != 0:
|
||||
struct.pack_into('B', self._bytes, pad_start, 0xff)
|
||||
pad_start += 1
|
||||
|
||||
# Create a padding section unless the padding size is smaller than the
|
||||
# size of a section head. Padding is allowed in the last section but
|
||||
# by convention bootconf.txt is the last section and there's no need to
|
||||
# pad to the end of the sector. This also ensures that the loopback
|
||||
# config read/write tests produce identical binaries.
|
||||
pad_bytes = next_offset - pad_start
|
||||
if pad_bytes > 8 and not is_last:
|
||||
pad_bytes -= 8
|
||||
struct.pack_into('>i', self._bytes, pad_start, PAD_MAGIC)
|
||||
pad_start += 4
|
||||
struct.pack_into('>i', self._bytes, pad_start, pad_bytes)
|
||||
pad_start += 4
|
||||
|
||||
debug("pad %d" % pad_bytes)
|
||||
pad = 0
|
||||
while pad < pad_bytes:
|
||||
struct.pack_into('B', self._bytes, pad_start + pad, 0xff)
|
||||
pad = pad + 1
|
||||
|
||||
def update_key(self, src_pem, dst_filename):
|
||||
"""
|
||||
Replaces the specified public key entry with the public key values extracted
|
||||
from the source PEM file.
|
||||
"""
|
||||
pubkey_bytes = pemtobin(src_pem)
|
||||
self.update(pubkey_bytes, dst_filename)
|
||||
|
||||
def update_file(self, src_filename, dst_filename):
|
||||
"""
|
||||
Replaces the contents of dst_filename in the EEPROM with the contents of src_file.
|
||||
"""
|
||||
src_bytes = open(src_filename, 'rb').read()
|
||||
if len(src_bytes) > MAX_FILE_SIZE:
|
||||
raise Exception("src file %s is too large (%d bytes). The maximum size is %d bytes."
|
||||
% (src_filename, len(src_bytes), MAX_FILE_SIZE))
|
||||
self.update(src_bytes, dst_filename)
|
||||
|
||||
def write(self):
|
||||
"""
|
||||
Writes the updated EEPROM image to stdout or the specified output file.
|
||||
"""
|
||||
if self._out is not None:
|
||||
self._out.write(self._bytes)
|
||||
self._out.close()
|
||||
else:
|
||||
if hasattr(sys.stdout, 'buffer'):
|
||||
sys.stdout.buffer.write(self._bytes)
|
||||
else:
|
||||
sys.stdout.write(self._bytes)
|
||||
|
||||
def get_file(self, filename):
|
||||
hdr_offset, length, is_last, next_offset = self.find_file(filename)
|
||||
offset = hdr_offset + 4 + FILE_HDR_LEN
|
||||
file_bytes = self._bytes[offset:offset+length-FILENAME_LEN-4]
|
||||
return file_bytes
|
||||
|
||||
def extract_files(self):
|
||||
for i in range(0, len(self._sections)):
|
||||
s = self._sections[i]
|
||||
if s.magic == FILE_MAGIC:
|
||||
file_bytes = self.get_file(s.filename)
|
||||
open(s.filename, 'wb').write(file_bytes)
|
||||
|
||||
def read(self):
|
||||
config_bytes = self.get_file('bootconf.txt')
|
||||
if self._out is not None:
|
||||
self._out.write(config_bytes)
|
||||
self._out.close()
|
||||
else:
|
||||
if hasattr(sys.stdout, 'buffer'):
|
||||
sys.stdout.buffer.write(config_bytes)
|
||||
else:
|
||||
sys.stdout.write(config_bytes)
|
||||
|
||||
def main():
|
||||
"""
|
||||
Utility for reading and writing the configuration file in the
|
||||
Raspberry Pi bootloader EEPROM image.
|
||||
"""
|
||||
description = """\
|
||||
Bootloader EEPROM configuration tool for the Raspberry Pi 4 and Raspberry Pi 5.
|
||||
Operating modes:
|
||||
|
||||
1. Outputs the current bootloader configuration to STDOUT if no arguments are
|
||||
specified OR the given output file if --out is specified.
|
||||
|
||||
rpi-eeprom-config [--out boot.conf]
|
||||
|
||||
2. Extracts the configuration file from the given 'eeprom' file and outputs
|
||||
the result to STDOUT or the output file if --output is specified.
|
||||
|
||||
rpi-eeprom-config pieeprom.bin [--out boot.conf]
|
||||
|
||||
3. Writes a new EEPROM image replacing the configuration file with the contents
|
||||
of the file specified by --config.
|
||||
|
||||
rpi-eeprom-config --config boot.conf --out newimage.bin pieeprom.bin
|
||||
|
||||
The new image file can be installed via rpi-eeprom-update
|
||||
rpi-eeprom-update -d -f newimage.bin
|
||||
|
||||
4. Applies a given config file to an EEPROM image and invokes rpi-eeprom-update
|
||||
to schedule an update of the bootloader when the system is rebooted.
|
||||
|
||||
Since this command launches rpi-eeprom-update to schedule the EEPROM update
|
||||
it must be run as root.
|
||||
|
||||
sudo rpi-eeprom-config --apply boot.conf [pieeprom.bin]
|
||||
|
||||
If the 'eeprom' argument is not specified then the latest available image
|
||||
is selected by calling 'rpi-eeprom-update -l'.
|
||||
|
||||
5. The '--edit' parameter behaves the same as '--apply' except that instead of
|
||||
applying a predefined configuration file a text editor is launched with the
|
||||
contents of the current EEPROM configuration.
|
||||
|
||||
Since this command launches rpi-eeprom-update to schedule the EEPROM update
|
||||
it must be run as root.
|
||||
|
||||
The configuration file will be taken from:
|
||||
* The blconfig reserved memory nvmem device
|
||||
* The cached bootloader configuration 'vcgencmd bootloader_config'
|
||||
* The current pending update - typically /boot/pieeprom.upd
|
||||
|
||||
sudo -E rpi-eeprom-config --edit [pieeprom.bin]
|
||||
|
||||
To cancel the pending update run 'sudo rpi-eeprom-update -r'
|
||||
|
||||
The default text editor is nano and may be overridden by setting the 'EDITOR'
|
||||
environment variable and passing '-E' to 'sudo' to preserve the environment.
|
||||
|
||||
6. Signing the bootloader config file.
|
||||
Updates an EEPROM binary with a signed config file (created by rpi-eeprom-digest) plus
|
||||
the corresponding RSA public key.
|
||||
|
||||
Requires Python Cryptodomex libraries and OpenSSL. To install on Raspberry Pi OS run:-
|
||||
sudo apt install openssl python-pip
|
||||
sudo python3 -m pip install cryptodomex
|
||||
|
||||
rpi-eeprom-digest -k private.pem -i bootconf.txt -o bootconf.sig
|
||||
rpi-eeprom-config --config bootconf.txt --digest bootconf.sig --pubkey public.pem --out pieeprom-signed.bin pieeprom.bin
|
||||
|
||||
Currently, the signing process is a separate step so can't be used with the --edit or --apply modes.
|
||||
|
||||
|
||||
See 'rpi-eeprom-update -h' for more information about the available EEPROM images.
|
||||
"""
|
||||
|
||||
if os.getuid() != 0:
|
||||
exit_error("Please run as root")
|
||||
elif not argon_rpisupported():
|
||||
# Skip
|
||||
sys.exit(0)
|
||||
argon_edit_config()
|
||||
|
||||
if __name__ == '__main__':
|
||||
atexit.register(exit_handler)
|
||||
main()
|
22
source/scripts/argon-shutdown.sh
Normal file
22
source/scripts/argon-shutdown.sh
Normal file
@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
pythonbin=/usr/bin/python3
|
||||
argononefanscript=/etc/argon/argononed.py
|
||||
argoneonrtcscript=/etc/argon/argoneond.py
|
||||
argonirconfigscript=/etc/argon/argonone-ir
|
||||
|
||||
if [ ! -z "$1" ]
|
||||
then
|
||||
$pythonbin $argononefanscript FANOFF
|
||||
if [ "$1" = "poweroff" ] || [ "$1" = "halt" ]
|
||||
then
|
||||
if [ -f $argonirconfigscript ]
|
||||
then
|
||||
if [ -f $argoneonrtcscript ]
|
||||
then
|
||||
$pythonbin $argoneonrtcscript SHUTDOWN
|
||||
fi
|
||||
$pythonbin $argononefanscript SHUTDOWN
|
||||
fi
|
||||
fi
|
||||
fi
|
106
source/scripts/argon-status.sh
Normal file
106
source/scripts/argon-status.sh
Normal file
@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
get_number () {
|
||||
read curnumber
|
||||
if [ -z "$curnumber" ]
|
||||
then
|
||||
echo "-2"
|
||||
return
|
||||
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||
then
|
||||
if [ $curnumber -lt 0 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
elif [ $curnumber -gt 100 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
fi
|
||||
echo $curnumber
|
||||
return
|
||||
fi
|
||||
echo "-1"
|
||||
return
|
||||
}
|
||||
|
||||
INSTALLATIONFOLDER=/etc/argon
|
||||
pythonbin="sudo /usr/bin/python3"
|
||||
argonstatusscript=$INSTALLATIONFOLDER/argonstatus.py
|
||||
argondashboardscript=$INSTALLATIONFOLDER/argondashboard.py
|
||||
argononefanscript=$INSTALLATIONFOLDER/argononed.py
|
||||
argoneonrtcscript=$INSTALLATIONFOLDER/argoneond.py
|
||||
|
||||
|
||||
echo "--------------------------"
|
||||
echo " Argon System Information"
|
||||
echo "--------------------------"
|
||||
|
||||
|
||||
loopflag=1
|
||||
while [ $loopflag -eq 1 ]
|
||||
do
|
||||
echo
|
||||
echo " 1. Temperatures"
|
||||
echo " 2. CPU Utilization"
|
||||
echo " 3. Storage Capacity"
|
||||
echo " 4. RAM"
|
||||
echo " 5. IP Address"
|
||||
lastoption=5
|
||||
if [ -f $argononefanscript ]
|
||||
then
|
||||
echo " 6. Fan Speed"
|
||||
lastoption=6
|
||||
fi
|
||||
if [ -f "$argoneonrtcscript" ]
|
||||
then
|
||||
echo " 7. RTC Schedules"
|
||||
echo " 8. RAID"
|
||||
lastoption=8
|
||||
fi
|
||||
lastoption=$((lastoption + 1))
|
||||
echo " ${lastoption}. Dashboard"
|
||||
echo
|
||||
echo " 0. Back"
|
||||
echo -n "Enter Number (0-${lastoption}):"
|
||||
|
||||
newmode=$( get_number )
|
||||
if [ $newmode -eq 0 ]
|
||||
then
|
||||
loopflag=0
|
||||
elif [ $newmode -gt 0 ] && [ $newmode -le $lastoption ]
|
||||
then
|
||||
echo "--------------------------"
|
||||
if [ $newmode -eq $lastoption ]
|
||||
then
|
||||
$pythonbin $argondashboardscript
|
||||
elif [ $newmode -eq 1 ]
|
||||
then
|
||||
$pythonbin $argonstatusscript "temperature"
|
||||
elif [ $newmode -eq 2 ]
|
||||
then
|
||||
$pythonbin $argonstatusscript "cpu usage"
|
||||
elif [ $newmode -eq 3 ]
|
||||
then
|
||||
$pythonbin $argonstatusscript "storage"
|
||||
elif [ $newmode -eq 4 ]
|
||||
then
|
||||
$pythonbin $argonstatusscript "ram"
|
||||
elif [ $newmode -eq 5 ]
|
||||
then
|
||||
$pythonbin $argonstatusscript "ip"
|
||||
elif [ $newmode -eq 6 ]
|
||||
then
|
||||
$pythonbin $argonstatusscript "temperature" "fan configuration" "fan speed"
|
||||
elif [ $newmode -eq 7 ]
|
||||
then
|
||||
$pythonbin $argoneonrtcscript GETSCHEDULELIST
|
||||
elif [ $newmode -eq 8 ]
|
||||
then
|
||||
$pythonbin $argonstatusscript "raid"
|
||||
fi
|
||||
echo "--------------------------"
|
||||
fi
|
||||
done
|
||||
|
131
source/scripts/argon-uninstall.sh
Normal file
131
source/scripts/argon-uninstall.sh
Normal file
@ -0,0 +1,131 @@
|
||||
#!/bin/bash
|
||||
echo "----------------------"
|
||||
echo " Argon Uninstall Tool"
|
||||
echo "----------------------"
|
||||
echo -n "Press Y to continue:"
|
||||
read -n 1 confirm
|
||||
echo
|
||||
if [ "$confirm" = "y" ]
|
||||
then
|
||||
confirm="Y"
|
||||
fi
|
||||
|
||||
if [ "$confirm" != "Y" ]
|
||||
then
|
||||
echo "Cancelled"
|
||||
exit
|
||||
fi
|
||||
|
||||
destfoldername=$USERNAME
|
||||
if [ -z "$destfoldername" ]
|
||||
then
|
||||
destfoldername=$USER
|
||||
fi
|
||||
if [ "$destfoldername" = "root" ]
|
||||
then
|
||||
destfoldername=""
|
||||
fi
|
||||
if [ -z "$destfoldername" ]
|
||||
then
|
||||
destfoldername="pi"
|
||||
fi
|
||||
|
||||
|
||||
shortcutfile="/home/$destfoldername/Desktop/argonone-config.desktop"
|
||||
if [ -f "$shortcutfile" ]; then
|
||||
sudo rm $shortcutfile
|
||||
if [ -f "/usr/share/pixmaps/ar1config.png" ]; then
|
||||
sudo rm /usr/share/pixmaps/ar1config.png
|
||||
fi
|
||||
if [ -f "/usr/share/pixmaps/argoneon.png" ]; then
|
||||
sudo rm /usr/share/pixmaps/argoneon.png
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
INSTALLATIONFOLDER=/etc/argon
|
||||
|
||||
argononefanscript=$INSTALLATIONFOLDER/argononed.py
|
||||
|
||||
if [ -f $argononefanscript ]; then
|
||||
sudo systemctl stop argononed.service
|
||||
sudo systemctl disable argononed.service
|
||||
|
||||
# Turn off the fan
|
||||
/usr/bin/python3 $argononefanscript FANOFF
|
||||
|
||||
# Remove files
|
||||
sudo rm /lib/systemd/system/argononed.service
|
||||
fi
|
||||
|
||||
# Remove RTC if any
|
||||
argoneonrtcscript=$INSTALLATIONFOLDER/argoneond.py
|
||||
if [ -f "$argoneonrtcscript" ]
|
||||
then
|
||||
# Disable Services
|
||||
sudo systemctl stop argoneond.service
|
||||
sudo systemctl disable argoneond.service
|
||||
|
||||
# No need for sudo
|
||||
/usr/bin/python3 $argoneonrtcscript CLEAN
|
||||
/usr/bin/python3 $argoneonrtcscript SHUTDOWN
|
||||
|
||||
# Remove files
|
||||
sudo rm /lib/systemd/system/argoneond.service
|
||||
fi
|
||||
|
||||
# Remove UPS daemon if any
|
||||
argononeupsscript=$INSTALLATIONFOLDER/argononeupsd.py
|
||||
if [ -f "$argononeupsscript" ]
|
||||
then
|
||||
sudo rmmod argonbatteryicon
|
||||
# Disable Services
|
||||
sudo systemctl stop argononeupsd.service
|
||||
sudo systemctl disable argononeupsd.service
|
||||
|
||||
sudo systemctl stop argonupsrtcd.service
|
||||
sudo systemctl disable argonupsrtcd.service
|
||||
|
||||
# Remove files
|
||||
sudo rm /lib/systemd/system/argononeupsd.service
|
||||
sudo rm /lib/systemd/system/argonupsrtcd.service
|
||||
|
||||
find "/home" -maxdepth 1 -type d | while read line; do
|
||||
shortcutfile="$line/Desktop/argonone-ups.desktop"
|
||||
if [ -f "$shortcutfile" ]; then
|
||||
sudo rm $shortcutfile
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
sudo rm /usr/bin/argon-config
|
||||
|
||||
if [ -f "/usr/bin/argonone-config" ]
|
||||
then
|
||||
sudo rm /usr/bin/argonone-config
|
||||
sudo rm /usr/bin/argonone-uninstall
|
||||
fi
|
||||
|
||||
|
||||
if [ -f "/usr/bin/argonone-ir" ]
|
||||
then
|
||||
sudo rm /usr/bin/argonone-ir
|
||||
fi
|
||||
|
||||
# Delete config files
|
||||
for configfile in argonunits argononed argononed-hdd argoneonrtc argoneonoled argonupsrtc
|
||||
do
|
||||
if [ -f "/etc/${configfile}.conf" ]
|
||||
then
|
||||
sudo rm "/etc/${configfile}.conf"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
|
||||
sudo rm /lib/systemd/system-shutdown/argon-shutdown.sh
|
||||
|
||||
sudo rm -R -f $INSTALLATIONFOLDER
|
||||
|
||||
echo "Removed Argon Services."
|
||||
echo "Cleanup will complete after restarting the device."
|
105
source/scripts/argon-unitconfig.sh
Normal file
105
source/scripts/argon-unitconfig.sh
Normal file
@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
|
||||
unitconfigfile=/etc/argonunits.conf
|
||||
|
||||
get_number () {
|
||||
read curnumber
|
||||
if [ -z "$curnumber" ]
|
||||
then
|
||||
echo "-2"
|
||||
return
|
||||
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||
then
|
||||
if [ $curnumber -lt 0 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
elif [ $curnumber -gt 100 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
fi
|
||||
echo $curnumber
|
||||
return
|
||||
fi
|
||||
echo "-1"
|
||||
return
|
||||
}
|
||||
|
||||
saveconfig () {
|
||||
echo "#" > $unitconfigfile
|
||||
echo "# Argon Unit Configuration" >> $unitconfigfile
|
||||
echo "#" >> $unitconfigfile
|
||||
echo "temperature=$1" >> $unitconfigfile
|
||||
}
|
||||
|
||||
updateconfig=1
|
||||
unitloopflag=1
|
||||
while [ $unitloopflag -eq 1 ]
|
||||
do
|
||||
if [ $updateconfig -eq 1 ]
|
||||
then
|
||||
. $unitconfigfile
|
||||
fi
|
||||
|
||||
updateconfig=0
|
||||
if [ -z "$temperature" ]
|
||||
then
|
||||
temperature="C"
|
||||
updateconfig=1
|
||||
fi
|
||||
|
||||
# Write default values to config file, daemon already uses default so no need to restart service
|
||||
if [ $updateconfig -eq 1 ]
|
||||
then
|
||||
saveconfig $temperature
|
||||
updateconfig=0
|
||||
fi
|
||||
|
||||
|
||||
echo "-----------------------------"
|
||||
echo "Argon Display Units"
|
||||
echo "-----------------------------"
|
||||
echo "Choose from the list:"
|
||||
echo " 1. Temperature: $temperature"
|
||||
echo
|
||||
echo " 0. Back"
|
||||
echo -n "Enter Number (0-1):"
|
||||
|
||||
newmode=$( get_number )
|
||||
if [ $newmode -eq 0 ]
|
||||
then
|
||||
unitloopflag=0
|
||||
elif [ $newmode -eq 1 ]
|
||||
then
|
||||
echo
|
||||
echo "-----------------------------"
|
||||
echo "Temperature Display"
|
||||
echo "-----------------------------"
|
||||
echo "Choose from the list:"
|
||||
echo " 1. Celsius"
|
||||
echo " 2. Fahrenheit"
|
||||
echo
|
||||
echo " 0. Cancel"
|
||||
echo -n "Enter Number (0-2):"
|
||||
|
||||
cmdmode=$( get_number )
|
||||
if [ $cmdmode -eq 1 ]
|
||||
then
|
||||
temperature="C"
|
||||
updateconfig=1
|
||||
elif [ $cmdmode -eq 2 ]
|
||||
then
|
||||
temperature="F"
|
||||
updateconfig=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $updateconfig -eq 1 ]
|
||||
then
|
||||
saveconfig $temperature
|
||||
sudo systemctl restart argononed.service
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
14
source/scripts/argon-versioninfo.sh
Normal file
14
source/scripts/argon-versioninfo.sh
Normal file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSIONINFO="2505003"
|
||||
|
||||
echo "Version $VERSIONINFO"
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
echo
|
||||
echo "We acknowledge the valuable feedback of the following:"
|
||||
echo "ghalfacree, NHHiker"
|
||||
echo
|
||||
echo "Feel free to join the discussions at https://forum.argon40.com"
|
||||
echo
|
||||
fi
|
371
source/scripts/argondashboard.py
Normal file
371
source/scripts/argondashboard.py
Normal file
@ -0,0 +1,371 @@
|
||||
#!/bin/python3
|
||||
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
|
||||
import signal
|
||||
import curses
|
||||
|
||||
|
||||
sys.path.append("/etc/argon/")
|
||||
from argonsysinfo import *
|
||||
from argonregister import *
|
||||
|
||||
|
||||
|
||||
############
|
||||
# Constants
|
||||
############
|
||||
COLORPAIRID_DEFAULT=1
|
||||
COLORPAIRID_LOGO=2
|
||||
COLORPAIRID_DEFAULTINVERSE=3
|
||||
COLORPAIRID_ALERT=4
|
||||
COLORPAIRID_WARNING=5
|
||||
COLORPAIRID_GOOD=6
|
||||
|
||||
|
||||
|
||||
|
||||
INPUTREFRESHMS=100
|
||||
DISPLAYREFRESHMS=5000
|
||||
UPS_LOGFILE="/dev/shm/upslog.txt"
|
||||
|
||||
|
||||
###################
|
||||
# Display Elements
|
||||
###################
|
||||
|
||||
def displaydatetime(stdscr):
|
||||
try:
|
||||
curtimenow = time.localtime()
|
||||
|
||||
stdscr.addstr(1, 1, time.strftime("%A", curtimenow), curses.color_pair(COLORPAIRID_DEFAULT))
|
||||
stdscr.addstr(2, 1, time.strftime("%b %d,%Y", curtimenow), curses.color_pair(COLORPAIRID_DEFAULT))
|
||||
stdscr.addstr(3, 1, time.strftime("%I:%M%p", curtimenow), curses.color_pair(COLORPAIRID_DEFAULT))
|
||||
except:
|
||||
pass
|
||||
|
||||
def displayipbattery(stdscr):
|
||||
try:
|
||||
displaytextright(stdscr,1, argonsysinfo_getip()+" ", COLORPAIRID_DEFAULT)
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
status = ""
|
||||
level = ""
|
||||
outobj = {}
|
||||
# Load status
|
||||
fp = open(UPS_LOGFILE, "r")
|
||||
logdata = fp.read()
|
||||
alllines = logdata.split("\n")
|
||||
ctr = 0
|
||||
while ctr < len(alllines):
|
||||
tmpval = alllines[ctr].strip()
|
||||
curinfo = tmpval.split(":")
|
||||
if len(curinfo) > 1:
|
||||
tmpattrib = curinfo[0].lower().split(" ")
|
||||
# The rest are assumed to be value
|
||||
outobj[tmpattrib[0]] = tmpval[(len(curinfo[0])+1):].strip()
|
||||
ctr = ctr + 1
|
||||
|
||||
# Map to data
|
||||
try:
|
||||
statuslist = outobj["power"].lower().split(" ")
|
||||
if statuslist[0] == "battery":
|
||||
tmp_charging = 0
|
||||
else:
|
||||
tmp_charging = 1
|
||||
tmp_battery = int(statuslist[1].replace("%",""))
|
||||
|
||||
colorpairidx = COLORPAIRID_DEFAULT
|
||||
if tmp_charging:
|
||||
if tmp_battery > 99:
|
||||
status="Plugged"
|
||||
level=""
|
||||
else:
|
||||
status="Charging"
|
||||
level=str(tmp_battery)+"%"
|
||||
else:
|
||||
status="Battery"
|
||||
level=str(tmp_battery)+"%"
|
||||
if tmp_battery <= 20:
|
||||
colorpairidx = COLORPAIRID_ALERT
|
||||
elif tmp_battery <= 50:
|
||||
colorpairidx = COLORPAIRID_WARNING
|
||||
else:
|
||||
colorpairidx = COLORPAIRID_GOOD
|
||||
|
||||
displaytextright(stdscr,2, status+" ", colorpairidx)
|
||||
displaytextright(stdscr,3, level+" ", colorpairidx)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
def displayramcpu(stdscr, refcpu, rowstart, colstart):
|
||||
curusage_b = argonsysinfo_getcpuusagesnapshot()
|
||||
try:
|
||||
outputlist = []
|
||||
tmpraminfo = argonsysinfo_getram()
|
||||
outputlist.append({"title": "ram ", "value": tmpraminfo[1]+" "+tmpraminfo[0]+" Free"})
|
||||
|
||||
for cpuname in refcpu:
|
||||
if cpuname == "cpu":
|
||||
continue
|
||||
if refcpu[cpuname]["total"] == curusage_b[cpuname]["total"]:
|
||||
outputlist.append({"title": cpuname, "value": "Loading"})
|
||||
else:
|
||||
total = curusage_b[cpuname]["total"]-refcpu[cpuname]["total"]
|
||||
idle = curusage_b[cpuname]["idle"]-refcpu[cpuname]["idle"]
|
||||
outputlist.append({"title": cpuname, "value": str(int(100*(total-idle)/(total)))+"% Used"})
|
||||
displaytitlevaluelist(stdscr, rowstart, colstart, outputlist)
|
||||
except:
|
||||
pass
|
||||
return curusage_b
|
||||
|
||||
|
||||
def displaytempfan(stdscr, rowstart, colstart):
|
||||
try:
|
||||
outputlist = []
|
||||
try:
|
||||
if busobj is not None:
|
||||
fanspeed = argonregister_getfanspeed(busobj)
|
||||
fanspeedstr = "Off"
|
||||
if fanspeed > 0:
|
||||
fanspeedstr = str(fanspeed)+"%"
|
||||
outputlist.append({"title": "Fan ", "value": fanspeedstr})
|
||||
except:
|
||||
pass
|
||||
# Todo load from config
|
||||
temperature = "C"
|
||||
hddtempctr = 0
|
||||
maxcval = 0
|
||||
mincval = 200
|
||||
|
||||
|
||||
# Get min/max of hdd temp
|
||||
hddtempobj = argonsysinfo_gethddtemp()
|
||||
for curdev in hddtempobj:
|
||||
if hddtempobj[curdev] < mincval:
|
||||
mincval = hddtempobj[curdev]
|
||||
if hddtempobj[curdev] > maxcval:
|
||||
maxcval = hddtempobj[curdev]
|
||||
hddtempctr = hddtempctr + 1
|
||||
|
||||
cpucval = argonsysinfo_getcputemp()
|
||||
if hddtempctr > 0:
|
||||
alltempobj = {"cpu": cpucval,"hdd min": mincval, "hdd max": maxcval}
|
||||
# Update max C val to CPU Temp if necessary
|
||||
if maxcval < cpucval:
|
||||
maxcval = cpucval
|
||||
|
||||
displayrowht = 8
|
||||
displayrow = 8
|
||||
for curdev in alltempobj:
|
||||
if temperature == "C":
|
||||
# Celsius
|
||||
tmpstr = str(alltempobj[curdev])
|
||||
if len(tmpstr) > 4:
|
||||
tmpstr = tmpstr[0:4]
|
||||
else:
|
||||
# Fahrenheit
|
||||
tmpstr = str(32+9*(alltempobj[curdev])/5)
|
||||
if len(tmpstr) > 5:
|
||||
tmpstr = tmpstr[0:5]
|
||||
if len(curdev) <= 3:
|
||||
outputlist.append({"title": curdev.upper(), "value": tmpstr +temperature})
|
||||
else:
|
||||
outputlist.append({"title": curdev.upper(), "value": tmpstr +temperature})
|
||||
else:
|
||||
maxcval = cpucval
|
||||
if temperature == "C":
|
||||
# Celsius
|
||||
tmpstr = str(cpucval)
|
||||
if len(tmpstr) > 4:
|
||||
tmpstr = tmpstr[0:4]
|
||||
else:
|
||||
# Fahrenheit
|
||||
tmpstr = str(32+9*(cpucval)/5)
|
||||
if len(tmpstr) > 5:
|
||||
tmpstr = tmpstr[0:5]
|
||||
|
||||
outputlist.append({"title": "Temp", "value": tmpstr +temperature})
|
||||
displaytitlevaluelist(stdscr, rowstart, colstart, outputlist)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def displaystorage(stdscr, rowstart, colstart):
|
||||
try:
|
||||
outputlist = []
|
||||
tmpobj = argonsysinfo_listhddusage()
|
||||
for curdev in tmpobj:
|
||||
outputlist.append({"title": curdev, "value": argonsysinfo_kbstr(tmpobj[curdev]['total'])+ " "+ str(int(100*tmpobj[curdev]['used']/tmpobj[curdev]['total']))+"% Used" })
|
||||
displaytitlevaluelist(stdscr, rowstart, colstart, outputlist)
|
||||
except:
|
||||
pass
|
||||
|
||||
##################
|
||||
# Helpers
|
||||
##################
|
||||
|
||||
# Initialize I2C Bus
|
||||
bus = argonregister_initializebusobj()
|
||||
|
||||
def handle_resize(signum, frame):
|
||||
# TODO: Not working?
|
||||
curses.update_lines_cols()
|
||||
# Ideally redraw here
|
||||
|
||||
def displaytitlevaluelist(stdscr, rowstart, leftoffset, curlist):
|
||||
rowidx = rowstart
|
||||
while rowidx < curses.LINES and len(curlist) > 0:
|
||||
curline = ""
|
||||
tmpitem = curlist.pop(0)
|
||||
curline = tmpitem["title"]+": "+str(tmpitem["value"])
|
||||
|
||||
stdscr.addstr(rowidx, leftoffset, curline)
|
||||
rowidx = rowidx + 1
|
||||
|
||||
|
||||
def displaytextcentered(stdscr, rownum, strval, colorpairidx = COLORPAIRID_DEFAULT):
|
||||
leftoffset = 0
|
||||
numchars = len(strval)
|
||||
if numchars < 1:
|
||||
return
|
||||
elif (numchars > curses.COLS):
|
||||
leftoffset = 0
|
||||
strval = strval[0:curses.COLS]
|
||||
else:
|
||||
leftoffset = (curses.COLS - numchars)>>1
|
||||
|
||||
stdscr.addstr(rownum, leftoffset, strval, curses.color_pair(colorpairidx))
|
||||
|
||||
|
||||
def displaytextright(stdscr, rownum, strval, colorpairidx = COLORPAIRID_DEFAULT):
|
||||
leftoffset = 0
|
||||
numchars = len(strval)
|
||||
if numchars < 1:
|
||||
return
|
||||
elif (numchars > curses.COLS):
|
||||
leftoffset = 0
|
||||
strval = strval[0:curses.COLS]
|
||||
else:
|
||||
leftoffset = curses.COLS - numchars
|
||||
|
||||
stdscr.addstr(rownum, leftoffset, strval, curses.color_pair(colorpairidx))
|
||||
|
||||
|
||||
def displaylinebreak(stdscr, rownum, colorpairidx = COLORPAIRID_DEFAULTINVERSE):
|
||||
strval = " "
|
||||
while len(strval) < curses.COLS:
|
||||
strval = strval + " "
|
||||
stdscr.addstr(rownum, 0, strval, curses.color_pair(colorpairidx))
|
||||
|
||||
|
||||
|
||||
|
||||
##################
|
||||
# Main Loop
|
||||
##################
|
||||
|
||||
def mainloop(stdscr):
|
||||
try:
|
||||
# Set up signal handler
|
||||
signal.signal(signal.SIGWINCH, handle_resize)
|
||||
|
||||
maxloopctr = int(DISPLAYREFRESHMS/INPUTREFRESHMS)
|
||||
sleepsecs = INPUTREFRESHMS/1000
|
||||
|
||||
loopctr = maxloopctr
|
||||
loopmode = True
|
||||
|
||||
stdscr = curses.initscr()
|
||||
|
||||
# Turn off echoing of keys, and enter cbreak mode,
|
||||
# where no buffering is performed on keyboard input
|
||||
curses.noecho()
|
||||
curses.cbreak()
|
||||
curses.curs_set(0)
|
||||
curses.start_color()
|
||||
|
||||
#curses.COLOR_BLACK
|
||||
#curses.COLOR_BLUE
|
||||
#curses.COLOR_CYAN
|
||||
#curses.COLOR_GREEN
|
||||
#curses.COLOR_MAGENTA
|
||||
#curses.COLOR_RED
|
||||
#curses.COLOR_WHITE
|
||||
#curses.COLOR_YELLOW
|
||||
|
||||
curses.init_pair(COLORPAIRID_DEFAULT, curses.COLOR_WHITE, curses.COLOR_BLACK)
|
||||
curses.init_pair(COLORPAIRID_LOGO, curses.COLOR_WHITE, curses.COLOR_RED)
|
||||
curses.init_pair(COLORPAIRID_DEFAULTINVERSE, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
||||
curses.init_pair(COLORPAIRID_ALERT, curses.COLOR_RED, curses.COLOR_BLACK)
|
||||
curses.init_pair(COLORPAIRID_WARNING, curses.COLOR_YELLOW, curses.COLOR_BLACK)
|
||||
curses.init_pair(COLORPAIRID_GOOD, curses.COLOR_GREEN, curses.COLOR_BLACK)
|
||||
|
||||
stdscr.nodelay(True)
|
||||
|
||||
refcpu = argonsysinfo_getcpuusagesnapshot()
|
||||
while True:
|
||||
try:
|
||||
key = stdscr.getch()
|
||||
# if key == ord('x') or key == ord('X'):
|
||||
# Any key
|
||||
if key > 0:
|
||||
break
|
||||
except curses.error:
|
||||
# No key was pressed
|
||||
pass
|
||||
|
||||
loopctr = loopctr + 1
|
||||
if loopctr >= maxloopctr:
|
||||
loopctr = 0
|
||||
# Screen refresh loop
|
||||
# Clear screen
|
||||
stdscr.clear()
|
||||
|
||||
displaytextcentered(stdscr, 0, " ", COLORPAIRID_LOGO)
|
||||
displaytextcentered(stdscr, 1, " Argon40 Dashboard ", COLORPAIRID_LOGO)
|
||||
displaytextcentered(stdscr, 2, " ", COLORPAIRID_LOGO)
|
||||
displaytextcentered(stdscr, 3, "Press any key to close")
|
||||
displaylinebreak(stdscr, 5)
|
||||
|
||||
# Display Elements
|
||||
displaydatetime(stdscr)
|
||||
displayipbattery(stdscr)
|
||||
|
||||
# Data Columns
|
||||
rowstart = 7
|
||||
colstart = 20
|
||||
refcpu = displayramcpu(stdscr, refcpu, rowstart, colstart)
|
||||
displaystorage(stdscr, rowstart, colstart+30)
|
||||
displaytempfan(stdscr, rowstart, colstart+60)
|
||||
|
||||
# Main refresh even
|
||||
stdscr.refresh()
|
||||
|
||||
time.sleep(sleepsecs)
|
||||
|
||||
except Exception as initerr:
|
||||
pass
|
||||
|
||||
##########
|
||||
# Cleanup
|
||||
##########
|
||||
|
||||
try:
|
||||
curses.curs_set(1)
|
||||
curses.echo()
|
||||
curses.nocbreak()
|
||||
curses.endwin()
|
||||
except Exception as closeerr:
|
||||
pass
|
||||
|
||||
curses.wrapper(mainloop)
|
294
source/scripts/argoneon-oledconfig.sh
Normal file
294
source/scripts/argoneon-oledconfig.sh
Normal file
@ -0,0 +1,294 @@
|
||||
#!/bin/bash
|
||||
|
||||
oledconfigfile=/etc/argoneonoled.conf
|
||||
|
||||
get_number () {
|
||||
read curnumber
|
||||
if [ -z "$curnumber" ]
|
||||
then
|
||||
echo "-2"
|
||||
return
|
||||
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||
then
|
||||
if [ $curnumber -lt 0 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
elif [ $curnumber -gt 100 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
fi
|
||||
echo $curnumber
|
||||
return
|
||||
fi
|
||||
echo "-1"
|
||||
return
|
||||
}
|
||||
|
||||
get_pagename() {
|
||||
if [ "$1" == "clock" ]
|
||||
then
|
||||
pagename="Current Date/Time"
|
||||
elif [ "$1" == "cpu" ]
|
||||
then
|
||||
pagename="CPU Utilization"
|
||||
elif [ "$1" == "storage" ]
|
||||
then
|
||||
pagename="Storage Utilization"
|
||||
elif [ "$1" == "raid" ]
|
||||
then
|
||||
pagename="RAID Information"
|
||||
elif [ "$1" == "ram" ]
|
||||
then
|
||||
pagename="Available RAM"
|
||||
elif [ "$1" == "temp" ]
|
||||
then
|
||||
pagename="CPU/HDD Temperature"
|
||||
elif [ "$1" == "ip" ]
|
||||
then
|
||||
pagename="IP Address"
|
||||
else
|
||||
pagename="Invalid"
|
||||
fi
|
||||
}
|
||||
|
||||
configure_pagelist () {
|
||||
pagemasterlist="clock cpu storage raid ram temp ip"
|
||||
newscreenlist="$1"
|
||||
pageloopflag=1
|
||||
while [ $pageloopflag -eq 1 ]
|
||||
do
|
||||
echo "--------------------------------"
|
||||
echo " OLED Pages "
|
||||
echo "--------------------------------"
|
||||
i=1
|
||||
for curpage in $newscreenlist
|
||||
do
|
||||
get_pagename $curpage
|
||||
echo " $i. Remove $pagename"
|
||||
i=$((i+1))
|
||||
done
|
||||
if [ $i -eq 1 ]
|
||||
then
|
||||
echo " No page configured"
|
||||
fi
|
||||
echo
|
||||
echo " $i. Add Page"
|
||||
echo
|
||||
echo " 0. Done"
|
||||
echo -n "Enter Number (0-$i):"
|
||||
|
||||
cmdmode=$( get_number )
|
||||
if [ $cmdmode -eq 0 ]
|
||||
then
|
||||
pageloopflag=0
|
||||
elif [[ $cmdmode -eq $i ]]
|
||||
then
|
||||
|
||||
echo "--------------------------------"
|
||||
echo " Choose Page to Add"
|
||||
echo "--------------------------------"
|
||||
echo
|
||||
i=1
|
||||
for curpage in $pagemasterlist
|
||||
do
|
||||
get_pagename $curpage
|
||||
echo " $i. $pagename"
|
||||
i=$((i+1))
|
||||
done
|
||||
|
||||
echo
|
||||
echo " 0. Cancel"
|
||||
echo -n "Enter Number (0-$i):"
|
||||
pagenum=$( get_number )
|
||||
if [[ $pagenum -ge 1 && $pagenum -le $i ]]
|
||||
then
|
||||
i=1
|
||||
for curpage in $pagemasterlist
|
||||
do
|
||||
if [ $i -eq $pagenum ]
|
||||
then
|
||||
if [ "$newscreenlist" == "" ]
|
||||
then
|
||||
newscreenlist="$curpage"
|
||||
else
|
||||
newscreenlist="$newscreenlist $curpage"
|
||||
fi
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
fi
|
||||
elif [[ $cmdmode -ge 1 && $cmdmode -lt $i ]]
|
||||
then
|
||||
tmpscreenlist=""
|
||||
i=1
|
||||
for curpage in $newscreenlist
|
||||
do
|
||||
if [ ! $i -eq $cmdmode ]
|
||||
then
|
||||
tmpscreenlist="$tmpscreenlist $curpage"
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
if [ "$tmpscreenlist" == "" ]
|
||||
then
|
||||
newscreenlist="$tmpscreenlist"
|
||||
else
|
||||
# Remove leading space
|
||||
newscreenlist="${tmpscreenlist:1}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
saveconfig () {
|
||||
echo "#" > $oledconfigfile
|
||||
echo "# Argon OLED Configuration" >> $oledconfigfile
|
||||
echo "#" >> $oledconfigfile
|
||||
echo "enabled=$1" >> $oledconfigfile
|
||||
echo "switchduration=$2" >> $oledconfigfile
|
||||
echo "screensaver=$3" >> $oledconfigfile
|
||||
echo "screenlist=\"$4\"" >> $oledconfigfile
|
||||
}
|
||||
|
||||
updateconfig=1
|
||||
oledloopflag=1
|
||||
while [ $oledloopflag -eq 1 ]
|
||||
do
|
||||
if [ $updateconfig -eq 1 ]
|
||||
then
|
||||
. $oledconfigfile
|
||||
fi
|
||||
|
||||
updateconfig=0
|
||||
if [ -z "$enabled" ]
|
||||
then
|
||||
enabled="Y"
|
||||
updateconfig=1
|
||||
fi
|
||||
|
||||
if [ -z "$screenlist" ]
|
||||
then
|
||||
screenlist="clock ip"
|
||||
updateconfig=1
|
||||
fi
|
||||
|
||||
if [ -z "$screensaver" ]
|
||||
then
|
||||
screensaver=120
|
||||
updateconfig=1
|
||||
fi
|
||||
|
||||
if [ -z "$switchduration" ]
|
||||
then
|
||||
switchduration=0
|
||||
updateconfig=1
|
||||
fi
|
||||
|
||||
# Write default values to config file, daemon already uses default so no need to restart service
|
||||
if [ $updateconfig -eq 1 ]
|
||||
then
|
||||
saveconfig $enabled $switchduration $screensaver "$screenlist"
|
||||
updateconfig=0
|
||||
fi
|
||||
|
||||
displaystring=": Manually"
|
||||
if [ $switchduration -gt 1 ]
|
||||
then
|
||||
displaystring="Every $switchduration secs"
|
||||
fi
|
||||
|
||||
echo "-----------------------------"
|
||||
echo "Argon OLED Configuration Tool"
|
||||
echo "-----------------------------"
|
||||
echo "Choose from the list:"
|
||||
echo " 1. Switch Page $displaystring"
|
||||
echo " 2. Configure Pages"
|
||||
echo " 3. Turn OFF OLED Screen when unchanged after $screensaver secs"
|
||||
echo " 4. Enable OLED Pages: $enabled"
|
||||
echo
|
||||
echo " 0. Back"
|
||||
echo -n "Enter Number (0-3):"
|
||||
|
||||
newmode=$( get_number )
|
||||
if [ $newmode -eq 0 ]
|
||||
then
|
||||
oledloopflag=0
|
||||
elif [ $newmode -eq 1 ]
|
||||
then
|
||||
echo
|
||||
echo -n "Enter # of Seconds (10-60, Manual if 0):"
|
||||
|
||||
cmdmode=$( get_number )
|
||||
if [ $cmdmode -eq 0 ]
|
||||
then
|
||||
switchduration=0
|
||||
updateconfig=1
|
||||
elif [[ $cmdmode -ge 10 && $cmdmode -le 60 ]]
|
||||
then
|
||||
updateconfig=1
|
||||
switchduration=$cmdmode
|
||||
else
|
||||
echo
|
||||
echo "Invalid duration"
|
||||
echo
|
||||
fi
|
||||
elif [ $newmode -eq 3 ]
|
||||
then
|
||||
echo
|
||||
echo -n "Enter # of Seconds (60 or above, Manual if 0):"
|
||||
|
||||
cmdmode=$( get_number )
|
||||
if [ $cmdmode -eq 0 ]
|
||||
then
|
||||
screensaver=0
|
||||
updateconfig=1
|
||||
elif [ $cmdmode -ge 60 ]
|
||||
then
|
||||
updateconfig=1
|
||||
screensaver=$cmdmode
|
||||
else
|
||||
echo
|
||||
echo "Invalid duration"
|
||||
echo
|
||||
fi
|
||||
elif [ $newmode -eq 2 ]
|
||||
then
|
||||
configure_pagelist "$screenlist"
|
||||
if [ ! "$screenlist" == "$newscreenlist" ]
|
||||
then
|
||||
screenlist="$newscreenlist"
|
||||
updateconfig=1
|
||||
fi
|
||||
elif [ $newmode -eq 4 ]
|
||||
then
|
||||
echo
|
||||
echo -n "Enable OLED Pages (Y/n)?:"
|
||||
read -n 1 confirm
|
||||
tmpenabled="$enabled"
|
||||
if [[ "$confirm" == "n" || "$confirm" == "N" ]]
|
||||
then
|
||||
tmpenabled="N"
|
||||
elif [[ "$confirm" == "y" || "$confirm" == "Y" ]]
|
||||
then
|
||||
tmpenabled="Y"
|
||||
else
|
||||
echo "Invalid response"
|
||||
fi
|
||||
if [ ! "$enabled" == "$tmpenabled" ]
|
||||
then
|
||||
enabled="$tmpenabled"
|
||||
updateconfig=1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
if [ $updateconfig -eq 1 ]
|
||||
then
|
||||
saveconfig $enabled $switchduration $screensaver "$screenlist"
|
||||
sudo systemctl restart argononed.service
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
421
source/scripts/argoneon-rtcconfig.sh
Normal file
421
source/scripts/argoneon-rtcconfig.sh
Normal file
@ -0,0 +1,421 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
rtcdaemonname=argoneond
|
||||
rtcconfigfile=/etc/argoneonrtc.conf
|
||||
else
|
||||
rtcdaemonname=${1}d
|
||||
rtcconfigfile=/etc/${1}.conf
|
||||
fi
|
||||
|
||||
|
||||
pythonbin=/usr/bin/python3
|
||||
argonrtcscript=/etc/argon/$rtcdaemonname.py
|
||||
|
||||
CHECKPLATFORM="Others"
|
||||
# Check if Raspbian
|
||||
grep -q -F 'Raspbian' /etc/os-release &> /dev/null
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
CHECKPLATFORM="Raspbian"
|
||||
else
|
||||
# Ubuntu needs elevated access for SMBus
|
||||
pythonbin="sudo /usr/bin/python3"
|
||||
fi
|
||||
|
||||
|
||||
get_number () {
|
||||
read curnumber
|
||||
if [ -z "$curnumber" ]
|
||||
then
|
||||
echo "-2"
|
||||
return
|
||||
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||
then
|
||||
if [ $curnumber -lt 0 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
elif [ $curnumber -gt 100 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
fi
|
||||
echo $curnumber
|
||||
return
|
||||
fi
|
||||
echo "-1"
|
||||
return
|
||||
}
|
||||
|
||||
configure_schedule () {
|
||||
scheduleloopflag=1
|
||||
while [ $scheduleloopflag -eq 1 ]
|
||||
do
|
||||
echo "--------------------------------"
|
||||
echo " Configure Schedule "
|
||||
echo "--------------------------------"
|
||||
echo " 1. Add Schedule"
|
||||
echo " or"
|
||||
echo " Remove Schedule"
|
||||
$pythonbin $argonrtcscript GETSCHEDULELIST
|
||||
echo
|
||||
echo " 99. Main Menu"
|
||||
echo " 0. Back"
|
||||
#echo "NOTE: You can also edit $rtcconfigfile directly"
|
||||
echo -n "Enter Number:"
|
||||
|
||||
newmode=$( get_number )
|
||||
if [ $newmode -eq 0 ]
|
||||
then
|
||||
scheduleloopflag=0
|
||||
elif [ $newmode -eq 99 ]
|
||||
then
|
||||
scheduleloopflag=0
|
||||
rtcloopflag=2
|
||||
elif [ $newmode -eq 1 ]
|
||||
then
|
||||
configure_newschedule
|
||||
elif [ $newmode -gt 1 ]
|
||||
then
|
||||
echo "CONFIRM SCHEDULE REMOVAL"
|
||||
$pythonbin $argonrtcscript SHOWSCHEDULE $newmode
|
||||
echo -n "Press Y to remove schedule #$newmode:"
|
||||
read -n 1 confirm
|
||||
if [ "$confirm" = "y" ]
|
||||
then
|
||||
confirm="Y"
|
||||
fi
|
||||
if [ "$confirm" = "Y" ]
|
||||
then
|
||||
$pythonbin $argonrtcscript REMOVESCHEDULE $newmode
|
||||
sudo systemctl restart $rtcdaemonname.service
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
configure_newschedule () {
|
||||
|
||||
cmdmode=1
|
||||
hour=8
|
||||
minute=0
|
||||
minuteprefix=":0"
|
||||
dayidx=0
|
||||
repeat=1
|
||||
|
||||
subloopflag=1
|
||||
while [ $subloopflag -eq 1 ]
|
||||
do
|
||||
minuteprefix=":0"
|
||||
if [ $minute -ge 10 ]
|
||||
then
|
||||
minuteprefix=":"
|
||||
fi
|
||||
|
||||
typestr="Shutdown"
|
||||
if [ $cmdmode -eq 1 ]
|
||||
then
|
||||
typestr="Startup"
|
||||
fi
|
||||
|
||||
daystr="Daily"
|
||||
if [ $dayidx -eq 1 ]
|
||||
then
|
||||
daystr="Mon"
|
||||
elif [ $dayidx -eq 2 ]
|
||||
then
|
||||
daystr="Tue"
|
||||
elif [ $dayidx -eq 3 ]
|
||||
then
|
||||
daystr="Wed"
|
||||
elif [ $dayidx -eq 4 ]
|
||||
then
|
||||
daystr="Thu"
|
||||
elif [ $dayidx -eq 5 ]
|
||||
then
|
||||
daystr="Fri"
|
||||
elif [ $dayidx -eq 6 ]
|
||||
then
|
||||
daystr="Sat"
|
||||
elif [ $dayidx -eq 7 ]
|
||||
then
|
||||
daystr="Sun"
|
||||
fi
|
||||
|
||||
repeatstr="Yes"
|
||||
if [ $repeat -eq 0 ]
|
||||
then
|
||||
repeatstr="Once"
|
||||
if [ $dayidx -eq 0 ]
|
||||
then
|
||||
daystr="Next Occurence"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "--------------------------------"
|
||||
echo " Configure Schedule"
|
||||
echo "--------------------------------"
|
||||
echo " 1. Type: $typestr"
|
||||
echo " 2. Set Time: $hour$minuteprefix$minute"
|
||||
echo " 3. Repeating: $repeatstr"
|
||||
echo " 4. Day: $daystr"
|
||||
echo
|
||||
echo " 5. Add Schedule"
|
||||
echo
|
||||
echo " 0. Cancel"
|
||||
echo -n "Enter Number (0-5):"
|
||||
|
||||
setmode=$( get_number )
|
||||
if [ $setmode -eq 0 ]
|
||||
then
|
||||
subloopflag=0
|
||||
elif [ $setmode -eq 1 ]
|
||||
then
|
||||
echo "--------------------------------"
|
||||
echo " Schedule Type "
|
||||
echo "--------------------------------"
|
||||
echo " 1. Startup"
|
||||
echo " 2. Shutdown"
|
||||
echo
|
||||
echo -n "Enter Number (1-2):"
|
||||
|
||||
tmpval=$( get_number )
|
||||
if [ $tmpval -eq 1 ]
|
||||
then
|
||||
cmdmode=1
|
||||
elif [ $tmpval -eq 2 ]
|
||||
then
|
||||
cmdmode=0
|
||||
else
|
||||
echo "Invalid Option"
|
||||
fi
|
||||
elif [ $setmode -eq 2 ]
|
||||
then
|
||||
echo -n "Enter Hour (0-23):"
|
||||
tmphour=$( get_number )
|
||||
echo -n "Enter Minute (0-59):"
|
||||
tmpminute=$( get_number )
|
||||
if [[ $tmpminute -ge 0 && $tmpminute -le 59 && $tmphour -ge 0 && $tmphour -le 23 ]]
|
||||
then
|
||||
minute=$tmpminute
|
||||
hour=$tmphour
|
||||
else
|
||||
echo "Invalid value(s)"
|
||||
fi
|
||||
elif [ $setmode -eq 3 ]
|
||||
then
|
||||
echo -n "Repeat schedule (Y/n)?:"
|
||||
read -n 1 confirm
|
||||
if [ "$confirm" = "y" ]
|
||||
then
|
||||
repeat=1
|
||||
else
|
||||
repeat=0
|
||||
fi
|
||||
elif [ $setmode -eq 4 ]
|
||||
then
|
||||
echo "Select Day of the Week:"
|
||||
echo " 0. Daily"
|
||||
echo " 1. Monday"
|
||||
echo " 2. Tuesday"
|
||||
echo " 3. Wednesday"
|
||||
echo " 4. Thursday"
|
||||
echo " 5. Friday"
|
||||
echo " 6. Saturday"
|
||||
echo " 7. Sunday"
|
||||
|
||||
echo -n "Enter Number (0-7):"
|
||||
tmpval=$( get_number )
|
||||
if [[ $tmpval -ge 0 && $tmpval -le 7 ]]
|
||||
then
|
||||
dayidx=$tmpval
|
||||
else
|
||||
echo "Invalid Option"
|
||||
fi
|
||||
elif [ $setmode -eq 5 ]
|
||||
then
|
||||
if [ $dayidx -eq 0 ]
|
||||
then
|
||||
cronweekday="*"
|
||||
elif [ $dayidx -eq 7 ]
|
||||
then
|
||||
cronweekday="7"
|
||||
else
|
||||
cronweekday=$dayidx
|
||||
fi
|
||||
cmdcode="off"
|
||||
if [ $cmdmode -eq 1 ]
|
||||
then
|
||||
cmdcode="on"
|
||||
fi
|
||||
|
||||
echo "$minute $hour * * $cronweekday $cmdcode" >> $rtcconfigfile
|
||||
sudo systemctl restart $rtcdaemonname.service
|
||||
subloopflag=0
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
configure_newcron () {
|
||||
subloopflag=1
|
||||
while [ $subloopflag -eq 1 ]
|
||||
do
|
||||
echo "--------------------------------"
|
||||
echo " Schedule Type "
|
||||
echo "--------------------------------"
|
||||
echo " 1. Startup"
|
||||
echo " 2. Shutdown"
|
||||
echo
|
||||
echo " 0. Cancel"
|
||||
echo -n "Enter Number (0-2):"
|
||||
|
||||
cmdmode=$( get_number )
|
||||
if [ $cmdmode -eq 0 ]
|
||||
then
|
||||
subloopflag=0
|
||||
elif [[ $cmdmode -ge 1 && $cmdmode -le 2 ]]
|
||||
then
|
||||
cmdcode="on"
|
||||
echo "--------------------------------"
|
||||
if [ $cmdmode -eq 1 ]
|
||||
then
|
||||
echo " Schedule Startup"
|
||||
else
|
||||
echo " Schedule Shutdown"
|
||||
cmdcode="off"
|
||||
fi
|
||||
echo "--------------------------------"
|
||||
echo "Select Schedule:"
|
||||
echo " 1. Hourly"
|
||||
echo " 2. Daily"
|
||||
echo " 3. Weekly"
|
||||
echo " 4. Monthly"
|
||||
echo
|
||||
echo " 0. Back"
|
||||
echo -n "Enter Number (0-4):"
|
||||
|
||||
newmode=$( get_number )
|
||||
if [[ $newmode -ge 1 && $newmode -le 4 ]]
|
||||
then
|
||||
echo ""
|
||||
if [ $cmdmode -eq 1 ]
|
||||
then
|
||||
echo "New Startup Schedule"
|
||||
else
|
||||
echo "New Shutdown Schedule"
|
||||
fi
|
||||
|
||||
if [ $newmode -eq 1 ]
|
||||
then
|
||||
echo -n "Enter Minute (0-59):"
|
||||
minute=$( get_number )
|
||||
if [[ $minute -ge 0 && $minute -le 59 ]]
|
||||
then
|
||||
echo "$minute * * * * $cmdcode" >> $rtcconfigfile
|
||||
sudo systemctl restart $rtcdaemonname.service
|
||||
subloopflag=0
|
||||
else
|
||||
echo "Invalid value"
|
||||
fi
|
||||
elif [ $newmode -eq 2 ]
|
||||
then
|
||||
echo -n "Enter Hour (0-23):"
|
||||
hour=$( get_number )
|
||||
echo -n "Enter Minute (0-59):"
|
||||
minute=$( get_number )
|
||||
if [[ $minute -ge 0 && $minute -le 59 && $hour -ge 0 && $hour -le 23 ]]
|
||||
then
|
||||
echo "$minute $hour * * * $cmdcode" >> $rtcconfigfile
|
||||
sudo systemctl restart $rtcdaemonname.service
|
||||
subloopflag=0
|
||||
else
|
||||
echo "Invalid value(s)"
|
||||
fi
|
||||
elif [ $newmode -eq 3 ]
|
||||
then
|
||||
echo "Select Day of the Week:"
|
||||
echo " 0. Sunday"
|
||||
echo " 1. Monday"
|
||||
echo " 2. Tuesday"
|
||||
echo " 3. Wednesday"
|
||||
echo " 4. Thursday"
|
||||
echo " 5. Friday"
|
||||
echo " 6. Saturday"
|
||||
|
||||
echo -n "Enter Number (0-6):"
|
||||
weekday=$( get_number )
|
||||
echo -n "Enter Hour (0-23):"
|
||||
hour=$( get_number )
|
||||
echo -n "Enter Minute (0-59):"
|
||||
minute=$( get_number )
|
||||
|
||||
if [[ $minute -ge 0 && $minute -le 59 && $hour -ge 0 && $hour -le 23 && $weekday -ge 0 && $weekday -le 6 ]]
|
||||
then
|
||||
echo "$minute $hour * * $weekday $cmdcode" >> $rtcconfigfile
|
||||
sudo systemctl restart $rtcdaemonname.service
|
||||
subloopflag=0
|
||||
else
|
||||
echo "Invalid value(s)"
|
||||
fi
|
||||
elif [ $newmode -eq 4 ]
|
||||
then
|
||||
echo -n "Enter Date (1-31):"
|
||||
monthday=$( get_number )
|
||||
if [[ $monthday -ge 29 ]]
|
||||
then
|
||||
echo "WARNING: This schedule will not trigger for certain months"
|
||||
fi
|
||||
echo -n "Enter Hour (0-23):"
|
||||
hour=$( get_number )
|
||||
echo -n "Enter Minute (0-59):"
|
||||
minute=$( get_number )
|
||||
|
||||
if [[ $minute -ge 0 && $minute -le 59 && $hour -ge 0 && $hour -le 23 && $monthday -ge 1 && $monthday -le 31 ]]
|
||||
then
|
||||
echo "$minute $hour $monthday * * $cmdcode" >> $rtcconfigfile
|
||||
sudo systemctl restart $rtcdaemonname.service
|
||||
subloopflag=0
|
||||
else
|
||||
echo "Invalid value(s)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
rtcloopflag=1
|
||||
while [ $rtcloopflag -eq 1 ]
|
||||
do
|
||||
echo "----------------------------"
|
||||
echo "Argon RTC Configuration Tool"
|
||||
echo "----------------------------"
|
||||
$pythonbin $argonrtcscript GETRTCTIME
|
||||
echo "Choose from the list:"
|
||||
echo " 1. Update RTC Time"
|
||||
echo " 2. Configure Startup/Shutdown Schedules"
|
||||
echo
|
||||
echo " 0. Exit"
|
||||
echo -n "Enter Number (0-2):"
|
||||
|
||||
newmode=$( get_number )
|
||||
if [ $newmode -eq 0 ]
|
||||
then
|
||||
rtcloopflag=0
|
||||
elif [[ $newmode -ge 1 && $newmode -le 2 ]]
|
||||
then
|
||||
if [ $newmode -eq 1 ]
|
||||
then
|
||||
echo "Matching RTC Time to System Time..."
|
||||
$pythonbin $argonrtcscript UPDATERTCTIME
|
||||
elif [ $newmode -eq 2 ]
|
||||
then
|
||||
configure_schedule
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
487
source/scripts/argoneond.py
Normal file
487
source/scripts/argoneond.py
Normal file
@ -0,0 +1,487 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
import math
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
sys.path.append("/etc/argon/")
|
||||
from argonregister import argonregister_initializebusobj
|
||||
import argonrtc
|
||||
|
||||
|
||||
# Initialize I2C Bus
|
||||
bus = argonregister_initializebusobj()
|
||||
|
||||
ADDR_RTC=0x51
|
||||
|
||||
#################
|
||||
# Common/Helpers
|
||||
#################
|
||||
|
||||
RTC_CONFIGFILE = "/etc/argoneonrtc.conf"
|
||||
|
||||
RTC_ALARM_BIT = 0x8
|
||||
RTC_TIMER_BIT = 0x4
|
||||
|
||||
# PCF8563 number system Binary Coded Decimal (BCD)
|
||||
|
||||
# BCD to Decimal
|
||||
def numBCDtoDEC(val):
|
||||
return (val & 0xf)+(((val >> 4) & 0xf)*10)
|
||||
|
||||
# Decimal to BCD
|
||||
def numDECtoBCD(val):
|
||||
return (math.floor(val/10)<<4) + (val % 10)
|
||||
|
||||
# Check if Event Bit is raised
|
||||
def hasRTCEventFlag(flagbit):
|
||||
if bus is None:
|
||||
return False
|
||||
bus.write_byte(ADDR_RTC,1)
|
||||
out = bus.read_byte_data(ADDR_RTC, 1)
|
||||
return (out & flagbit) != 0
|
||||
|
||||
# Clear Event Bit if raised
|
||||
def clearRTCEventFlag(flagbit):
|
||||
if bus is None:
|
||||
return False
|
||||
|
||||
out = bus.read_byte_data(ADDR_RTC, 1)
|
||||
if (out & flagbit) != 0:
|
||||
# Unset only if fired
|
||||
bus.write_byte_data(ADDR_RTC, 1, out&(0xff-flagbit))
|
||||
return True
|
||||
return False
|
||||
|
||||
# Enable Event Flag
|
||||
def setRTCEventFlag(flagbit, enabled):
|
||||
if bus is None:
|
||||
return
|
||||
|
||||
# 0x10 = TI_TP flag, 0 by default
|
||||
ti_tp_flag = 0x10
|
||||
# flagbit=0x4 for timer flag, 0x1 for enable timer flag
|
||||
# flagbit=0x8 for alarm flag, 0x2 for enable alarm flag
|
||||
enableflagbit = flagbit>>2
|
||||
disableflagbit = 0
|
||||
if enabled == False:
|
||||
disableflagbit = enableflagbit
|
||||
enableflagbit = 0
|
||||
|
||||
out = bus.read_byte_data(ADDR_RTC, 1)
|
||||
bus.write_byte_data(ADDR_RTC, 1, (out&(0xff-flagbit-disableflagbit - ti_tp_flag))|enableflagbit)
|
||||
|
||||
|
||||
#########
|
||||
# Describe Methods
|
||||
#########
|
||||
|
||||
# Describe Timer Setting
|
||||
def describeTimer(showsetting):
|
||||
if bus is None:
|
||||
return "Error"
|
||||
|
||||
out = bus.read_byte_data(ADDR_RTC, 14)
|
||||
tmp = out & 3
|
||||
if tmp == 3:
|
||||
outstr = " Minute(s)"
|
||||
elif tmp == 2:
|
||||
outstr = " Second(s)"
|
||||
elif tmp == 1:
|
||||
outstr = "/64th Second"
|
||||
elif tmp == 0:
|
||||
outstr = "/4096th Second"
|
||||
|
||||
if (out & 0x80) != 0:
|
||||
out = bus.read_byte_data(ADDR_RTC, 15)
|
||||
return "Every "+(numBCDtoDEC(out)+1)+outstr
|
||||
elif showsetting == True:
|
||||
return "Disabled (Interval every 1"+outstr+")"
|
||||
# Setting might matter to save resources
|
||||
return "None"
|
||||
|
||||
|
||||
# Describe Alarm Setting
|
||||
def describeAlarm():
|
||||
if bus is None:
|
||||
return "Error"
|
||||
|
||||
minute = -1
|
||||
hour = -1
|
||||
caldate = -1
|
||||
weekday = -1
|
||||
|
||||
out = bus.read_byte_data(ADDR_RTC, 9)
|
||||
if (out & 0x80) == 0:
|
||||
minute = numBCDtoDEC(out & 0x7f)
|
||||
|
||||
out = bus.read_byte_data(ADDR_RTC, 10)
|
||||
if (out & 0x80) == 0:
|
||||
hour = numBCDtoDEC(out & 0x3f)
|
||||
|
||||
out = bus.read_byte_data(ADDR_RTC, 11)
|
||||
if (out & 0x80) == 0:
|
||||
caldate = numBCDtoDEC(out & 0x3f)
|
||||
|
||||
out = bus.read_byte_data(ADDR_RTC, 12)
|
||||
if (out & 0x80) == 0:
|
||||
weekday = numBCDtoDEC(out & 0x7)
|
||||
|
||||
if weekday < 0 and caldate < 0 and hour < 0 and minute < 0:
|
||||
return "None"
|
||||
|
||||
# Convert from UTC
|
||||
utcschedule = argonrtc.describeSchedule([-1], [weekday], [caldate], [hour], [minute])
|
||||
weekday, caldate, hour, minute = argonrtc.convertAlarmTimezone(weekday, caldate, hour, minute, False)
|
||||
|
||||
return argonrtc.describeSchedule([-1], [weekday], [caldate], [hour], [minute]) + " Local (RTC Schedule: "+utcschedule+" UTC)"
|
||||
|
||||
|
||||
# Describe Control Flags
|
||||
def describeControlRegisters():
|
||||
if bus is None:
|
||||
print("Error")
|
||||
return
|
||||
|
||||
out = bus.read_byte_data(ADDR_RTC, 1)
|
||||
|
||||
print("\n***************")
|
||||
print("Control Status 2")
|
||||
print("\tTI_TP Flag:", ((out & 0x10) != 0))
|
||||
print("\tAlarm Flag:", ((out & RTC_ALARM_BIT) != 0),"( Enabled =", (out & (RTC_ALARM_BIT>>2)) != 0, ")")
|
||||
print("\tTimer Flag:", ((out & RTC_TIMER_BIT) != 0),"( Enabled =", (out & (RTC_TIMER_BIT>>2)) != 0, ")")
|
||||
|
||||
print("Alarm Setting:")
|
||||
print("\t"+describeAlarm())
|
||||
|
||||
print("Timer Setting:")
|
||||
print("\t"+describeTimer(True))
|
||||
|
||||
print("***************\n")
|
||||
|
||||
|
||||
#########
|
||||
# Alarm
|
||||
#########
|
||||
|
||||
# Check if RTC Alarm Flag is ON
|
||||
def hasRTCAlarmFlag():
|
||||
return hasRTCEventFlag(RTC_ALARM_BIT)
|
||||
|
||||
# Clear RTC Alarm Flag
|
||||
def clearRTCAlarmFlag():
|
||||
return clearRTCEventFlag(RTC_ALARM_BIT)
|
||||
|
||||
# Enables RTC Alarm Register
|
||||
def enableAlarm(registeraddr, value, mask):
|
||||
if bus is None:
|
||||
return
|
||||
|
||||
# 0x00 is Enabled
|
||||
bus.write_byte_data(ADDR_RTC, registeraddr, (numDECtoBCD(value)&mask))
|
||||
|
||||
# Disables RTC Alarm Register
|
||||
def disableAlarm(registeraddr):
|
||||
if bus is None:
|
||||
return
|
||||
|
||||
# 0x80 is disabled
|
||||
bus.write_byte_data(ADDR_RTC, registeraddr, 0x80)
|
||||
|
||||
# Removes all alarm settings
|
||||
def removeRTCAlarm():
|
||||
setRTCEventFlag(RTC_ALARM_BIT, False)
|
||||
|
||||
disableAlarm(9)
|
||||
disableAlarm(10)
|
||||
disableAlarm(11)
|
||||
disableAlarm(12)
|
||||
|
||||
# Set RTC Alarm (Negative values ignored)
|
||||
def setRTCAlarm(enableflag, weekday, caldate, hour, minute):
|
||||
|
||||
weekday, caldate, hour, minute = argonrtc.getRTCAlarm(weekday, caldate, hour, minute)
|
||||
if caldate < 1 and weekday < 0 and hour < 0 and minute < 0:
|
||||
return -1
|
||||
|
||||
clearRTCAlarmFlag()
|
||||
setRTCEventFlag(RTC_ALARM_BIT, enableflag)
|
||||
|
||||
if minute >= 0:
|
||||
enableAlarm(9, minute, 0x7f)
|
||||
else:
|
||||
disableAlarm(9)
|
||||
|
||||
if hour >= 0:
|
||||
enableAlarm(10, hour, 0x7f)
|
||||
else:
|
||||
disableAlarm(10)
|
||||
|
||||
if caldate >= 0:
|
||||
enableAlarm(11, caldate, 0x7f)
|
||||
else:
|
||||
disableAlarm(11)
|
||||
|
||||
if weekday >= 0:
|
||||
# 0 - Sun (datetime 0 - Mon)
|
||||
if weekday > 5:
|
||||
weekday = 0
|
||||
else:
|
||||
weekday = weekday + 1
|
||||
enableAlarm(12, weekday, 0x7f)
|
||||
else:
|
||||
disableAlarm(12)
|
||||
|
||||
return 0
|
||||
|
||||
# Set RTC Hourly Alarm
|
||||
def setRTCAlarmHourly(enableflag, minute):
|
||||
return setRTCAlarm(enableflag, -1, -1, -1, minute)
|
||||
|
||||
# Set RTC Daily Alarm
|
||||
def setRTCAlarmDaily(enableflag, hour, minute):
|
||||
return setRTCAlarm(enableflag, -1, -1, hour, minute)
|
||||
|
||||
# Set RTC Weekly Alarm
|
||||
def setRTCAlarmWeekly(enableflag, dayofweek, hour, minute):
|
||||
return setRTCAlarm(enableflag, dayofweek, -1, hour, minute)
|
||||
|
||||
# Set RTC Monthly Alarm
|
||||
def setRTCAlarmMonthly(enableflag, caldate, hour, minute):
|
||||
return setRTCAlarm(enableflag, -1, caldate, hour, minute)
|
||||
|
||||
#########
|
||||
# Timer
|
||||
#########
|
||||
|
||||
# Check if RTC Timer Flag is ON
|
||||
def hasRTCTimerFlag():
|
||||
return hasRTCEventFlag(RTC_TIMER_BIT)
|
||||
|
||||
# Clear RTC Timer Flag
|
||||
def clearRTCTimerFlag():
|
||||
return clearRTCEventFlag(RTC_TIMER_BIT)
|
||||
|
||||
# Remove RTC Timer Setting
|
||||
def removeRTCTimer():
|
||||
if bus is None:
|
||||
return
|
||||
|
||||
setRTCEventFlag(RTC_TIMER_BIT, False)
|
||||
|
||||
# Timer disable and Set Timer frequency to lowest (0x3=1 per minute)
|
||||
bus.write_byte_data(ADDR_RTC, 14, 3)
|
||||
bus.write_byte_data(ADDR_RTC, 15, 0)
|
||||
|
||||
# Set RTC Timer Interval
|
||||
def setRTCTimerInterval(enableflag, value, inSeconds = False):
|
||||
if bus is None:
|
||||
return -1
|
||||
|
||||
if value > 255 or value < 1:
|
||||
return -1
|
||||
clearRTCTimerFlag()
|
||||
setRTCEventFlag(RTC_TIMER_BIT, enableflag)
|
||||
|
||||
# 0x80 Timer Enabled, mode: 0x3=1/Min, 0x2=1/Sec, 0x1=Per 64th Sec, 0=Per 4096th Sec
|
||||
timerconfigFlag = 0x83
|
||||
if inSeconds == True:
|
||||
timerconfigFlag = 0x82
|
||||
|
||||
bus.write_byte_data(ADDR_RTC, 14, timerconfigFlag)
|
||||
bus.write_byte_data(ADDR_RTC, 15, numDECtoBCD(value&0xff))
|
||||
return 0
|
||||
|
||||
#############
|
||||
# Date/Time
|
||||
#############
|
||||
|
||||
# Returns RTC timestamp as datetime object
|
||||
def getRTCdatetime():
|
||||
if bus is None:
|
||||
return datetime.datetime(2000, 1, 1, 0, 0, 0)
|
||||
|
||||
# Data Sheet Recommends to read this manner (instead of from registers)
|
||||
bus.write_byte(ADDR_RTC,2)
|
||||
|
||||
out = bus.read_byte(ADDR_RTC)
|
||||
out = numBCDtoDEC(out & 0x7f)
|
||||
second = out
|
||||
#warningflag = (out & 0x80)>>7
|
||||
|
||||
out = bus.read_byte(ADDR_RTC)
|
||||
minute = numBCDtoDEC(out & 0x7f)
|
||||
|
||||
out = bus.read_byte(ADDR_RTC)
|
||||
hour = numBCDtoDEC(out & 0x3f)
|
||||
|
||||
out = bus.read_byte(ADDR_RTC)
|
||||
caldate = numBCDtoDEC(out & 0x3f)
|
||||
|
||||
out = bus.read_byte(ADDR_RTC)
|
||||
#weekDay = numBCDtoDEC(out & 7)
|
||||
|
||||
out = bus.read_byte(ADDR_RTC)
|
||||
month = numBCDtoDEC(out & 0x1f)
|
||||
|
||||
out = bus.read_byte(ADDR_RTC)
|
||||
year = numBCDtoDEC(out)
|
||||
|
||||
#print({"year":year, "month": month, "date": caldate, "hour": hour, "minute": minute, "second": second})
|
||||
|
||||
if month == 0:
|
||||
# Reset, uninitialized RTC
|
||||
month = 1
|
||||
|
||||
# Timezone is GMT/UTC +0
|
||||
# Year is from 2000
|
||||
try:
|
||||
return datetime.datetime(year+2000, month, caldate, hour, minute, second)+argonrtc.getLocaltimeOffset()
|
||||
except:
|
||||
return datetime.datetime(2000, 1, 1, 0, 0, 0)
|
||||
|
||||
# set RTC time using datetime object (Local time)
|
||||
def setRTCdatetime(localdatetime):
|
||||
if bus is None:
|
||||
return
|
||||
# Set local time to UTC
|
||||
localdatetime = localdatetime - argonrtc.getLocaltimeOffset()
|
||||
|
||||
# python Sunday = 6, RTC Sunday = 0
|
||||
weekDay = localdatetime.weekday()
|
||||
if weekDay == 6:
|
||||
weekDay = 0
|
||||
else:
|
||||
weekDay = weekDay + 1
|
||||
|
||||
# Write to respective registers
|
||||
bus.write_byte_data(ADDR_RTC,2,numDECtoBCD(localdatetime.second))
|
||||
bus.write_byte_data(ADDR_RTC,3,numDECtoBCD(localdatetime.minute))
|
||||
bus.write_byte_data(ADDR_RTC,4,numDECtoBCD(localdatetime.hour))
|
||||
bus.write_byte_data(ADDR_RTC,5,numDECtoBCD(localdatetime.day))
|
||||
bus.write_byte_data(ADDR_RTC,6,numDECtoBCD(weekDay))
|
||||
bus.write_byte_data(ADDR_RTC,7,numDECtoBCD(localdatetime.month))
|
||||
|
||||
# Year is from 2000
|
||||
bus.write_byte_data(ADDR_RTC,8,numDECtoBCD(localdatetime.year-2000))
|
||||
|
||||
|
||||
#########
|
||||
# Config
|
||||
#########
|
||||
|
||||
# Set Next Alarm on RTC
|
||||
def setNextAlarm(commandschedulelist, prevdatetime):
|
||||
nextcommandtime, weekday, caldate, hour, minute = argonrtc.getNextAlarm(commandschedulelist, prevdatetime)
|
||||
if prevdatetime >= nextcommandtime:
|
||||
return prevdatetime
|
||||
if weekday < 0 and caldate < 0 and hour < 0 and minute < 0:
|
||||
# No schedule
|
||||
# nextcommandtime is current time, which will be replaced/checked next iteration
|
||||
removeRTCAlarm()
|
||||
return nextcommandtime
|
||||
|
||||
setRTCAlarm(True, nextcommandtime.weekday(), nextcommandtime.day, nextcommandtime.hour, nextcommandtime.minute)
|
||||
return nextcommandtime
|
||||
|
||||
|
||||
def allowshutdown():
|
||||
uptime = 0.0
|
||||
errorflag = False
|
||||
try:
|
||||
cpuctr = 0
|
||||
tempfp = open("/proc/uptime", "r")
|
||||
alllines = tempfp.readlines()
|
||||
for temp in alllines:
|
||||
infolist = temp.split(" ")
|
||||
if len(infolist) > 1:
|
||||
uptime = float(infolist[0])
|
||||
break
|
||||
tempfp.close()
|
||||
except IOError:
|
||||
errorflag = True
|
||||
# 120=2mins minimum up time
|
||||
return uptime > 120
|
||||
|
||||
######
|
||||
if len(sys.argv) > 1:
|
||||
cmd = sys.argv[1].upper()
|
||||
|
||||
# Enable Alarm/Timer Flags
|
||||
enableflag = True
|
||||
|
||||
if cmd == "CLEAN":
|
||||
removeRTCAlarm()
|
||||
removeRTCTimer()
|
||||
elif cmd == "SHUTDOWN":
|
||||
clearRTCAlarmFlag()
|
||||
clearRTCTimerFlag()
|
||||
|
||||
elif cmd == "GETRTCSCHEDULE":
|
||||
print("Alarm Setting:")
|
||||
print("\t"+describeAlarm())
|
||||
#print("Timer Setting:")
|
||||
#print("\t"+describeTimer(True))
|
||||
|
||||
elif cmd == "GETRTCTIME":
|
||||
print("RTC Time:", getRTCdatetime())
|
||||
|
||||
elif cmd == "UPDATERTCTIME":
|
||||
setRTCdatetime(datetime.datetime.now())
|
||||
print("RTC Time:", getRTCdatetime())
|
||||
|
||||
elif cmd == "GETSCHEDULELIST":
|
||||
argonrtc.describeConfigList(RTC_CONFIGFILE)
|
||||
|
||||
elif cmd == "SHOWSCHEDULE":
|
||||
if len(sys.argv) > 2:
|
||||
if sys.argv[2].isdigit():
|
||||
# Display starts at 2, maps to 0-based index
|
||||
configidx = int(sys.argv[2])-2
|
||||
configlist = argonrtc.loadConfigList(RTC_CONFIGFILE)
|
||||
if len(configlist) > configidx:
|
||||
print (" ",argonrtc.describeConfigListEntry(configlist[configidx]))
|
||||
else:
|
||||
print(" Invalid Schedule")
|
||||
|
||||
elif cmd == "REMOVESCHEDULE":
|
||||
if len(sys.argv) > 2:
|
||||
if sys.argv[2].isdigit():
|
||||
# Display starts at 2, maps to 0-based index
|
||||
configidx = int(sys.argv[2])-2
|
||||
argonrtc.removeConfigEntry(RTC_CONFIGFILE, configidx)
|
||||
|
||||
elif cmd == "SERVICE":
|
||||
argonrtc.updateSystemTime(getRTCdatetime())
|
||||
|
||||
commandschedulelist = argonrtc.formCommandScheduleList(argonrtc.loadConfigList(RTC_CONFIGFILE))
|
||||
nextrtcalarmtime = setNextAlarm(commandschedulelist, datetime.datetime.now())
|
||||
serviceloop = True
|
||||
while serviceloop==True:
|
||||
clearRTCAlarmFlag()
|
||||
clearRTCTimerFlag()
|
||||
|
||||
tmpcurrenttime = datetime.datetime.now()
|
||||
if nextrtcalarmtime <= tmpcurrenttime:
|
||||
# Update RTC Alarm to next iteration
|
||||
nextrtcalarmtime = setNextAlarm(commandschedulelist, nextrtcalarmtime)
|
||||
if len(argonrtc.getCommandForTime(commandschedulelist, tmpcurrenttime, "off")) > 0:
|
||||
# Shutdown detected, issue command then end service loop
|
||||
if allowshutdown():
|
||||
os.system("shutdown now -h")
|
||||
serviceloop = False
|
||||
# Don't break to sleep while command executes (prevents service to restart)
|
||||
|
||||
|
||||
time.sleep(60)
|
||||
|
||||
|
||||
elif False:
|
||||
print("System Time: ", datetime.datetime.now())
|
||||
print("RTC Time: ", getRTCdatetime())
|
||||
|
||||
describeControlRegisters()
|
10
source/scripts/argoneond.service
Normal file
10
source/scripts/argoneond.service
Normal file
@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Argon EON RTC Service
|
||||
After=multi-user.target
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
RemainAfterExit=true
|
||||
ExecStart=/usr/bin/python3 /etc/argon/argoneond.py SERVICE
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
345
source/scripts/argoneonoled.py
Normal file
345
source/scripts/argoneonoled.py
Normal file
@ -0,0 +1,345 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
import math
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
# Initialize I2C Bus
|
||||
import smbus
|
||||
|
||||
try:
|
||||
bus=smbus.SMBus(1)
|
||||
except Exception:
|
||||
try:
|
||||
# Older version
|
||||
bus=smbus.SMBus(0)
|
||||
except Exception:
|
||||
print("Unable to detect i2c")
|
||||
bus=None
|
||||
|
||||
|
||||
OLED_WD=128
|
||||
OLED_HT=64
|
||||
OLED_SLAVEADDRESS=0x6a
|
||||
ADDR_OLED=0x3c
|
||||
|
||||
OLED_NUMFONTCHAR=256
|
||||
|
||||
OLED_BUFFERIZE = ((OLED_WD*OLED_HT)>>3)
|
||||
oled_imagebuffer = [0] * OLED_BUFFERIZE
|
||||
|
||||
|
||||
def oled_getmaxY():
|
||||
return OLED_HT
|
||||
|
||||
def oled_getmaxX():
|
||||
return OLED_WD
|
||||
|
||||
def oled_loadbg(bgname):
|
||||
if bgname == "bgblack":
|
||||
oled_clearbuffer()
|
||||
return
|
||||
elif bgname == "bgwhite":
|
||||
oled_clearbuffer(1)
|
||||
return
|
||||
try:
|
||||
file = open("/etc/argon/oled/"+bgname+".bin", "rb")
|
||||
bgbytes = list(file.read())
|
||||
file.close()
|
||||
ctr = len(bgbytes)
|
||||
if ctr == OLED_BUFFERIZE:
|
||||
oled_imagebuffer[:] = bgbytes
|
||||
elif ctr > OLED_BUFFERIZE:
|
||||
oled_imagebuffer[:] = bgbytes[0:OLED_BUFFERIZE]
|
||||
else:
|
||||
oled_imagebuffer[0:ctr] = bgbytes
|
||||
# Clear the rest of the buffer
|
||||
while ctr < OLED_BUFFERIZE:
|
||||
oled_imagebuffer[ctr] = 0
|
||||
ctr=ctr+1
|
||||
except FileNotFoundError:
|
||||
oled_clearbuffer()
|
||||
|
||||
|
||||
def oled_clearbuffer(value = 0):
|
||||
if value != 0:
|
||||
value = 0xff
|
||||
ctr = 0
|
||||
while ctr < OLED_BUFFERIZE:
|
||||
oled_imagebuffer[ctr] = value
|
||||
ctr=ctr+1
|
||||
|
||||
def oled_writebyterow(x,y,bytevalue, mode = 0):
|
||||
bufferoffset = OLED_WD*(y>>3) + x
|
||||
if mode == 0:
|
||||
oled_imagebuffer[bufferoffset] = bytevalue
|
||||
elif mode == 1:
|
||||
oled_imagebuffer[bufferoffset] = bytevalue^oled_imagebuffer[bufferoffset]
|
||||
else:
|
||||
oled_imagebuffer[bufferoffset] = bytevalue|oled_imagebuffer[bufferoffset]
|
||||
|
||||
|
||||
def oled_writebuffer(x,y,value, mode = 0):
|
||||
|
||||
yoffset = y>>3
|
||||
yshift = y&0x7
|
||||
ybit = (1<<yshift)
|
||||
|
||||
ymask = 0xFF^ybit
|
||||
|
||||
if value != 0:
|
||||
value = ybit
|
||||
|
||||
bufferoffset = OLED_WD*yoffset + x
|
||||
|
||||
curval = oled_imagebuffer[bufferoffset]
|
||||
if mode & 1:
|
||||
oled_imagebuffer[bufferoffset] = curval^value
|
||||
else:
|
||||
oled_imagebuffer[bufferoffset] = curval&ymask|value
|
||||
|
||||
|
||||
def oled_fill(value):
|
||||
oled_clearbuffer(value)
|
||||
oled_flushimage()
|
||||
|
||||
def oled_flushimage(hidescreen = True):
|
||||
if hidescreen == True:
|
||||
# Reset/Hide screen
|
||||
oled_power(False)
|
||||
|
||||
xctr = 0
|
||||
while xctr < OLED_WD:
|
||||
yctr = 0
|
||||
while yctr < OLED_HT:
|
||||
oled_flushblock(xctr, yctr)
|
||||
yctr = yctr + 8
|
||||
xctr = xctr + 32
|
||||
|
||||
if hidescreen == True:
|
||||
# Display
|
||||
oled_power(True)
|
||||
|
||||
|
||||
def oled_flushblock(xoffset, yoffset):
|
||||
yoffset = yoffset>>3
|
||||
blocksize = 32
|
||||
if bus is None:
|
||||
return
|
||||
try:
|
||||
# Set COM-H Addressing
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x20)
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x1)
|
||||
|
||||
# Set Column range
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x21)
|
||||
bus.write_byte_data(ADDR_OLED, 0, xoffset)
|
||||
bus.write_byte_data(ADDR_OLED, 0, xoffset+blocksize-1)
|
||||
|
||||
# Set Row Range
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x22)
|
||||
bus.write_byte_data(ADDR_OLED, 0, yoffset)
|
||||
bus.write_byte_data(ADDR_OLED, 0, yoffset)
|
||||
|
||||
# Set Display Start Line
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x40)
|
||||
|
||||
bufferoffset = OLED_WD*yoffset + xoffset
|
||||
# Write Out Buffer
|
||||
bus.write_i2c_block_data(ADDR_OLED, OLED_SLAVEADDRESS, oled_imagebuffer[bufferoffset:(bufferoffset+blocksize)])
|
||||
except:
|
||||
return
|
||||
|
||||
def oled_drawfilledrectangle(x, y, wd, ht, mode = 0):
|
||||
ymax = y + ht
|
||||
cury = y&0xF8
|
||||
|
||||
xmax = x + wd
|
||||
curx = x
|
||||
if ((y & 0x7)) != 0:
|
||||
yshift = y&0x7
|
||||
bytevalue = (0xFF<<yshift)&0xFF
|
||||
|
||||
# If 8 no additional masking needed
|
||||
if ymax-cury < 8:
|
||||
yshift = 8-((ymax-cury)&0x7)
|
||||
bytevalue = bytevalue & (0xFF>>yshift)
|
||||
|
||||
while curx < xmax:
|
||||
oled_writebyterow(curx,cury,bytevalue, mode)
|
||||
curx = curx + 1
|
||||
cury = cury + 8
|
||||
# Draw 8 rows at a time when possible
|
||||
while cury + 8 < ymax:
|
||||
curx = x
|
||||
while curx < xmax:
|
||||
oled_writebyterow(curx,cury,0xFF, mode)
|
||||
curx = curx + 1
|
||||
cury = cury + 8
|
||||
|
||||
if cury < ymax:
|
||||
yshift = 8-((ymax-cury)&0x7)
|
||||
bytevalue = (0xFF>>yshift)
|
||||
|
||||
curx = x
|
||||
while curx < xmax:
|
||||
oled_writebyterow(curx,cury,bytevalue, mode)
|
||||
curx = curx + 1
|
||||
|
||||
|
||||
def oled_writetextaligned(textdata, x, y, boxwidth, alignmode, charwd = 6, mode = 0):
|
||||
leftoffset = 0
|
||||
if alignmode == 1:
|
||||
# Centered
|
||||
leftoffset = (boxwidth-len(textdata)*charwd)>>1
|
||||
elif alignmode == 2:
|
||||
# Right aligned
|
||||
leftoffset = (boxwidth-len(textdata)*charwd)
|
||||
|
||||
oled_writetext(textdata, x+leftoffset, y, charwd, mode)
|
||||
|
||||
|
||||
def oled_writetext(textdata, x, y, charwd = 6, mode = 0):
|
||||
if charwd < 6:
|
||||
charwd = 6
|
||||
|
||||
charht = int((charwd<<3)/6)
|
||||
if charht & 0x7:
|
||||
charht = (charht&0xF8) + 8
|
||||
|
||||
try:
|
||||
file = open("/etc/argon/oled/font"+str(charht)+"x"+str(charwd)+".bin", "rb")
|
||||
fontbytes = list(file.read())
|
||||
file.close()
|
||||
except FileNotFoundError:
|
||||
try:
|
||||
# Default to smallest
|
||||
file = open("/etc/argon/oled/font8x6.bin", "rb")
|
||||
fontbytes = list(file.read())
|
||||
file.close()
|
||||
except FileNotFoundError:
|
||||
return
|
||||
|
||||
if ((y & 0x7)) == 0:
|
||||
# Use optimized loading
|
||||
oled_fastwritetext(textdata, x, y, charht, charwd, fontbytes, mode)
|
||||
return
|
||||
|
||||
numfontrow = charht>>3
|
||||
ctr = 0
|
||||
while ctr < len(textdata):
|
||||
fontoffset = ord(textdata[ctr])*charwd
|
||||
fontcol = 0
|
||||
while fontcol < charwd and x < OLED_WD:
|
||||
fontrow = 0
|
||||
row = y
|
||||
while fontrow < numfontrow and row < OLED_HT and x >= 0:
|
||||
curbit = 0x80
|
||||
curbyte = (fontbytes[fontoffset + fontcol + (OLED_NUMFONTCHAR*charwd*fontrow)])
|
||||
subrow = 0
|
||||
while subrow < 8 and row < OLED_HT:
|
||||
value = 0
|
||||
if (curbyte&curbit) != 0:
|
||||
value = 1
|
||||
oled_writebuffer(x,row,value, mode)
|
||||
curbit = curbit >> 1
|
||||
row = row + 1
|
||||
subrow = subrow + 1
|
||||
fontrow = fontrow + 1
|
||||
fontcol = fontcol + 1
|
||||
x = x + 1
|
||||
ctr = ctr + 1
|
||||
|
||||
def oled_fastwritetext(textdata, x, y, charht, charwd, fontbytes, mode = 0):
|
||||
|
||||
numfontrow = charht>>3
|
||||
ctr = 0
|
||||
while ctr < len(textdata):
|
||||
fontoffset = ord(textdata[ctr])*charwd
|
||||
fontcol = 0
|
||||
while fontcol < charwd and x < OLED_WD:
|
||||
fontrow = 0
|
||||
row = y&0xF8
|
||||
while fontrow < numfontrow and row < OLED_HT and x >= 0:
|
||||
curbyte = (fontbytes[fontoffset + fontcol + (OLED_NUMFONTCHAR*charwd*fontrow)])
|
||||
oled_writebyterow(x,row,curbyte, mode)
|
||||
fontrow = fontrow + 1
|
||||
row = row + 8
|
||||
fontcol = fontcol + 1
|
||||
x = x + 1
|
||||
ctr = ctr + 1
|
||||
return
|
||||
|
||||
|
||||
def oled_power(turnon = True):
|
||||
cmd = 0xAE
|
||||
if turnon == True:
|
||||
cmd = cmd|1
|
||||
if bus is None:
|
||||
return
|
||||
try:
|
||||
bus.write_byte_data(ADDR_OLED, 0, cmd)
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
def oled_inverse(enable = True):
|
||||
cmd = 0xA6
|
||||
if enable == True:
|
||||
cmd = cmd|1
|
||||
if bus is None:
|
||||
return
|
||||
try:
|
||||
bus.write_byte_data(ADDR_OLED, 0, cmd)
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
def oled_fullwhite(enable = True):
|
||||
cmd = 0xA4
|
||||
if enable == True:
|
||||
cmd = cmd|1
|
||||
if bus is None:
|
||||
return
|
||||
|
||||
try:
|
||||
bus.write_byte_data(ADDR_OLED, 0, cmd)
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
|
||||
def oled_reset():
|
||||
if bus is None:
|
||||
return
|
||||
try:
|
||||
# Set COM-H Addressing
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x20)
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x1)
|
||||
|
||||
# Set Column range
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x21)
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0)
|
||||
bus.write_byte_data(ADDR_OLED, 0, OLED_WD-1)
|
||||
|
||||
# Set Row Range
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x22)
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0)
|
||||
bus.write_byte_data(ADDR_OLED, 0, (OLED_HT>>3)-1)
|
||||
|
||||
# Set Page Addressing
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x20)
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x2)
|
||||
# Set GDDRAM Address
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0xB0)
|
||||
|
||||
# Set Display Start Line
|
||||
bus.write_byte_data(ADDR_OLED, 0, 0x40)
|
||||
except:
|
||||
return
|
||||
|
||||
|
254
source/scripts/argonone-fanconfig.sh
Normal file
254
source/scripts/argonone-fanconfig.sh
Normal file
@ -0,0 +1,254 @@
|
||||
#!/bin/bash
|
||||
|
||||
daemonconfigfile=/etc/argononed.conf
|
||||
unitconfigfile=/etc/argonunits.conf
|
||||
fanmode="CPU"
|
||||
|
||||
if [ "$1" == "hdd" ]
|
||||
then
|
||||
daemonconfigfile=/etc/argononed-hdd.conf
|
||||
fanmode="HDD"
|
||||
fi
|
||||
|
||||
if [ -f "$unitconfigfile" ]
|
||||
then
|
||||
. $unitconfigfile
|
||||
fi
|
||||
|
||||
if [ -z "$temperature" ]
|
||||
then
|
||||
temperature="C"
|
||||
fi
|
||||
|
||||
echo "------------------------------------------"
|
||||
echo " Argon Fan Speed Configuration Tool ($fanmode)"
|
||||
echo "------------------------------------------"
|
||||
echo "WARNING: This will remove existing configuration."
|
||||
echo -n "Press Y to continue:"
|
||||
read -n 1 confirm
|
||||
echo
|
||||
|
||||
|
||||
fanloopflag=1
|
||||
newmode=0
|
||||
if [ "$confirm" = "y" ]
|
||||
then
|
||||
confirm="Y"
|
||||
fi
|
||||
|
||||
if [ "$confirm" != "Y" ]
|
||||
then
|
||||
fanloopflag=0
|
||||
echo "Cancelled."
|
||||
else
|
||||
echo "Thank you."
|
||||
fi
|
||||
|
||||
get_number () {
|
||||
read curnumber
|
||||
if [ -z "$curnumber" ]
|
||||
then
|
||||
echo "-2"
|
||||
return
|
||||
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||
then
|
||||
if [ $curnumber -lt 0 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
elif [ $curnumber -gt 212 ]
|
||||
then
|
||||
# 212F = 100C
|
||||
echo "-1"
|
||||
return
|
||||
fi
|
||||
echo $curnumber
|
||||
return
|
||||
fi
|
||||
echo "-1"
|
||||
return
|
||||
}
|
||||
|
||||
while [ $fanloopflag -eq 1 ]
|
||||
do
|
||||
echo
|
||||
echo "Select fan mode:"
|
||||
echo " 1. Always on"
|
||||
if [ "$fanmode" == "HDD" ]
|
||||
then
|
||||
if [ "$temperature" == "C" ]
|
||||
then
|
||||
echo " 2. Adjust to temperatures (35C, 40C, and 45C)"
|
||||
else
|
||||
echo " 2. Adjust to temperatures (95F, 104F, and 113F)"
|
||||
fi
|
||||
else
|
||||
if [ "$temperature" == "C" ]
|
||||
then
|
||||
echo " 2. Adjust to temperatures (55C, 60C, and 65C)"
|
||||
else
|
||||
echo " 2. Adjust to temperatures (130F, 140F, and 150F)"
|
||||
fi
|
||||
fi
|
||||
echo " 3. Customize temperature cut-offs"
|
||||
echo
|
||||
echo " 0. Exit"
|
||||
echo "NOTE: You can also edit $daemonconfigfile directly"
|
||||
echo -n "Enter Number (0-3):"
|
||||
newmode=$( get_number )
|
||||
|
||||
if [[ $newmode -eq 0 ]]
|
||||
then
|
||||
fanloopflag=0
|
||||
elif [ $newmode -eq 1 ]
|
||||
then
|
||||
echo "#" > $daemonconfigfile
|
||||
echo "# Argon Fan Speed Configuration $fanmode" >> $daemonconfigfile
|
||||
echo "#" >> $daemonconfigfile
|
||||
echo "# Min Temp=Fan Speed" >> $daemonconfigfile
|
||||
|
||||
errorfanflag=1
|
||||
while [ $errorfanflag -eq 1 ]
|
||||
do
|
||||
echo -n "Please provide fan speed (30-100 only):"
|
||||
|
||||
curfan=$( get_number )
|
||||
if [ $curfan -ge 30 ]
|
||||
then
|
||||
errorfanflag=0
|
||||
elif [ $curfan -gt 100 ]
|
||||
then
|
||||
errorfanflag=0
|
||||
fi
|
||||
done
|
||||
|
||||
echo "1="$curfan >> $daemonconfigfile
|
||||
sudo systemctl restart argononed.service
|
||||
echo "Fan always on."
|
||||
elif [ $newmode -eq 2 ]
|
||||
then
|
||||
echo "#" > $daemonconfigfile
|
||||
echo "# Argon Fan Speed Configuration $fanmode" >> $daemonconfigfile
|
||||
echo "#" >> $daemonconfigfile
|
||||
echo "# Min Temp=Fan Speed" >> $daemonconfigfile
|
||||
|
||||
echo "Please provide fan speeds for the following temperatures:"
|
||||
curtemp=55
|
||||
maxtemp=70
|
||||
if [ "$fanmode" == "HDD" ]
|
||||
then
|
||||
curtemp=30
|
||||
maxtemp=60
|
||||
fi
|
||||
while [ $curtemp -lt $maxtemp ]
|
||||
do
|
||||
errorfanflag=1
|
||||
while [ $errorfanflag -eq 1 ]
|
||||
do
|
||||
displaytemp=$curtemp
|
||||
if [ "$temperature" == "F" ]
|
||||
then
|
||||
# Convert C to F
|
||||
displaytemp=$((($curtemp*9/5)+32))
|
||||
fi
|
||||
echo -n ""$displaytemp"$temperature (30-100 only):"
|
||||
|
||||
curfan=$( get_number )
|
||||
if [ $curfan -ge 30 ]
|
||||
then
|
||||
errorfanflag=0
|
||||
elif [ $curfan -gt 100 ]
|
||||
then
|
||||
errorfanflag=0
|
||||
fi
|
||||
done
|
||||
echo $curtemp"="$curfan >> $daemonconfigfile
|
||||
curtemp=$((curtemp+5))
|
||||
done
|
||||
|
||||
sudo systemctl restart argononed.service
|
||||
echo "Configuration updated."
|
||||
elif [ $newmode -eq 3 ]
|
||||
then
|
||||
echo "Please provide fan speeds and temperature pairs"
|
||||
echo
|
||||
|
||||
subloopflag=1
|
||||
paircounter=0
|
||||
while [ $subloopflag -eq 1 ]
|
||||
do
|
||||
errortempflag=1
|
||||
errorfanflag=1
|
||||
echo "(You may set a blank value to end configuration)"
|
||||
while [ $errortempflag -eq 1 ]
|
||||
do
|
||||
echo -n "Provide minimum temperature of $fanmode (in $temperature) then [ENTER]:"
|
||||
|
||||
curtemp=$( get_number )
|
||||
if [ $curtemp -ge 0 ]
|
||||
then
|
||||
errortempflag=0
|
||||
elif [ $curtemp -eq -2 ]
|
||||
then
|
||||
# Blank
|
||||
errortempflag=0
|
||||
errorfanflag=0
|
||||
subloopflag=0
|
||||
fi
|
||||
done
|
||||
while [ $errorfanflag -eq 1 ]
|
||||
do
|
||||
echo -n "Provide fan speed for "$curtemp"$temperature (30-100) then [ENTER]:"
|
||||
curfan=$( get_number )
|
||||
if [ $curfan -ge 30 ]
|
||||
then
|
||||
errorfanflag=0
|
||||
elif [ $curfan -gt 100 ]
|
||||
then
|
||||
errorfanflag=0
|
||||
elif [ $curfan -eq -2 ]
|
||||
then
|
||||
# Blank
|
||||
errortempflag=0
|
||||
errorfanflag=0
|
||||
subloopflag=0
|
||||
fi
|
||||
done
|
||||
if [ $subloopflag -eq 1 ]
|
||||
then
|
||||
if [ $paircounter -eq 0 ]
|
||||
then
|
||||
echo "#" > $daemonconfigfile
|
||||
echo "# Argon Fan Configuration" >> $daemonconfigfile
|
||||
echo "#" >> $daemonconfigfile
|
||||
echo "# Min Temp=Fan Speed" >> $daemonconfigfile
|
||||
fi
|
||||
|
||||
displaytemp=$curtemp
|
||||
paircounter=$((paircounter+1))
|
||||
if [ "$temperature" == "F" ]
|
||||
then
|
||||
# Convert to F to C
|
||||
curtemp=$((($curtemp-32)*5/9))
|
||||
fi
|
||||
echo $curtemp"="$curfan >> $daemonconfigfile
|
||||
|
||||
echo "* Fan speed will be set to "$curfan" once $fanmode temperature reaches "$displaytemp"$temperature"
|
||||
echo
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
if [ $paircounter -gt 0 ]
|
||||
then
|
||||
echo "Thank you! We saved "$paircounter" pairs."
|
||||
sudo systemctl restart argononed.service
|
||||
echo "Changes should take effect now."
|
||||
else
|
||||
echo "Cancelled, no data saved."
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
|
@ -1,5 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
if [ -e /boot/firmware/config.txt ] ; then
|
||||
FIRMWARE=/firmware
|
||||
else
|
||||
@ -24,9 +25,10 @@ then
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "--------------------------------"
|
||||
echo "Argon One IR Configuration Tool"
|
||||
echo "--------------------------------"
|
||||
|
||||
echo "-----------------------------"
|
||||
echo " Argon IR Configuration Tool"
|
||||
echo "------------------------------"
|
||||
echo "WARNING: This only supports NEC"
|
||||
echo " protocol only."
|
||||
echo -n "Press Y to continue:"
|
||||
@ -70,8 +72,8 @@ get_number () {
|
||||
}
|
||||
|
||||
irexecrcfile=/etc/lirc/irexec.lircrc
|
||||
irexecshfile=/usr/bin/argonirexec
|
||||
irdecodefile=/usr/bin/argonirdecoder
|
||||
irexecshfile=/etc/argon/argonirexec
|
||||
irdecodefile=/etc/argon/argonirdecoder
|
||||
kodiuserdatafolder="$HOME/.kodi/userdata"
|
||||
kodilircmapfile="$kodiuserdatafolder/Lircmap.xml"
|
||||
remotemode=""
|
||||
@ -176,9 +178,9 @@ then
|
||||
fi
|
||||
elif [ $newmode -eq 2 ]
|
||||
then
|
||||
echo "--------------------------------"
|
||||
echo "Argon One IR Configuration Tool"
|
||||
echo "--------------------------------"
|
||||
echo "-----------------------------"
|
||||
echo " Argon IR Configuration Tool"
|
||||
echo "-----------------------------"
|
||||
echo "WARNING: This will install LIRC"
|
||||
echo " and related libraries."
|
||||
echo -n "Press Y to agree:"
|
||||
@ -320,7 +322,10 @@ then
|
||||
echo ' <down>KEY_DOWN</down>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
echo ' <select>KEY_OK</select>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
echo ' <start>KEY_HOME</start>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
echo ' <rootmenu>KEY_MENUBACK</rootmenu>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
# 20240611: User reported mapping is incorrect
|
||||
#echo ' <rootmenu>KEY_MENUBACK</rootmenu>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
echo ' <rootmenu>KEY_MENU</rootmenu>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
echo ' <back>KEY_BACK</back>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
echo ' <volumeplus>KEY_VOLUMEUP</volumeplus>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
echo ' <volumeminus>KEY_VOLUMEDOWN</volumeminus>' | tee -a $kodilircmapfile 1> /dev/null
|
||||
echo ' </remote>' | tee -a $kodilircmapfile 1> /dev/null
|
305
source/scripts/argonone-upsconfig.sh
Normal file
305
source/scripts/argonone-upsconfig.sh
Normal file
@ -0,0 +1,305 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
if [ -e /boot/firmware/config.txt ] ; then
|
||||
FIRMWARE=/firmware
|
||||
else
|
||||
FIRMWARE=
|
||||
fi
|
||||
CONFIG=/boot${FIRMWARE}/config.txt
|
||||
|
||||
CHECKGPIOMODE="libgpiod" # gpiod or rpigpio
|
||||
|
||||
# Check if Raspbian, Ubuntu, others
|
||||
CHECKPLATFORM="Others"
|
||||
CHECKPLATFORMVERSION=""
|
||||
CHECKPLATFORMVERSIONNUM=""
|
||||
if [ -f "/etc/os-release" ]
|
||||
then
|
||||
source /etc/os-release
|
||||
if [ "$ID" = "raspbian" ]
|
||||
then
|
||||
CHECKPLATFORM="Raspbian"
|
||||
CHECKPLATFORMVERSION=$VERSION_ID
|
||||
elif [ "$ID" = "debian" ]
|
||||
then
|
||||
# For backwards compatibility, continue using raspbian
|
||||
CHECKPLATFORM="Raspbian"
|
||||
CHECKPLATFORMVERSION=$VERSION_ID
|
||||
elif [ "$ID" = "ubuntu" ]
|
||||
then
|
||||
CHECKPLATFORM="Ubuntu"
|
||||
CHECKPLATFORMVERSION=$VERSION_ID
|
||||
fi
|
||||
echo ${CHECKPLATFORMVERSION} | grep -e "\." > /dev/null
|
||||
if [ $? -eq 0 ]
|
||||
then
|
||||
CHECKPLATFORMVERSIONNUM=`cut -d "." -f2 <<< $CHECKPLATFORMVERSION `
|
||||
CHECKPLATFORMVERSION=`cut -d "." -f1 <<< $CHECKPLATFORMVERSION `
|
||||
fi
|
||||
fi
|
||||
|
||||
pythonbin=/usr/bin/python3
|
||||
|
||||
# Files
|
||||
ARGONDOWNLOADSERVER=https://download.argon40.com
|
||||
INSTALLATIONFOLDER=/etc/argon
|
||||
basename="argononeups"
|
||||
daemonname=$basename"d"
|
||||
|
||||
daemonupsservice=/lib/systemd/system/$daemonname.service
|
||||
upsdaemonscript=$INSTALLATIONFOLDER/$daemonname.py
|
||||
|
||||
rtcdaemonname="argonupsrtcd"
|
||||
|
||||
daemonrtcservice=/lib/systemd/system/$rtcdaemonname.service
|
||||
rtcdaemonscript=$INSTALLATIONFOLDER/$rtcdaemonname.py
|
||||
|
||||
|
||||
requireinstall=0
|
||||
newmode=0
|
||||
echo "-----------------------------------"
|
||||
echo " Argon Industria UPS Configuration"
|
||||
echo "-----------------------------------"
|
||||
if [ ! -f "$upsdaemonscript" ]
|
||||
then
|
||||
echo "Install Argon Industria UPS Tools"
|
||||
echo -n "Press Y to continue:"
|
||||
read -n 1 confirm
|
||||
echo
|
||||
|
||||
if [ "$confirm" = "y" ]
|
||||
then
|
||||
confirm="Y"
|
||||
fi
|
||||
|
||||
if [ "$confirm" != "Y" ]
|
||||
then
|
||||
echo "Cancelled"
|
||||
exit
|
||||
fi
|
||||
|
||||
requireinstall=1
|
||||
newmode=3 # Reinstall
|
||||
|
||||
fi
|
||||
|
||||
|
||||
get_number () {
|
||||
read curnumber
|
||||
if [ -z "$curnumber" ]
|
||||
then
|
||||
echo "-2"
|
||||
return
|
||||
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||
then
|
||||
if [ $curnumber -lt 0 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
elif [ $curnumber -gt 100 ]
|
||||
then
|
||||
echo "-1"
|
||||
return
|
||||
fi
|
||||
echo $curnumber
|
||||
return
|
||||
fi
|
||||
echo "-1"
|
||||
return
|
||||
}
|
||||
|
||||
UPSCMDFILE="/dev/shm/upscmd.txt"
|
||||
UPSSTATUSFILE="/dev/shm/upslog.txt"
|
||||
rtcconfigscript=$INSTALLATIONFOLDER/argonups-rtcconfig.sh
|
||||
|
||||
if [ -f "$UPSSTATUSFILE" ]
|
||||
then
|
||||
# cat $UPSSTATUSFILE
|
||||
sudo $pythonbin $rtcdaemonscript GETBATTERY
|
||||
fi
|
||||
|
||||
|
||||
loopflag=1
|
||||
while [ $loopflag -eq 1 ]
|
||||
do
|
||||
if [ $requireinstall -eq 0 ]
|
||||
then
|
||||
echo
|
||||
echo "Select option:"
|
||||
echo " 1. UPS Battery Status"
|
||||
echo " 2. Configure RTC and/or Schedule"
|
||||
echo " 3. Reinstall UPS Tools"
|
||||
echo " 4. Uninstall UPS Tools"
|
||||
echo ""
|
||||
echo " 0. Back"
|
||||
|
||||
echo -n "Enter Number (0-4):"
|
||||
|
||||
newmode=$( get_number )
|
||||
fi
|
||||
if [[ $newmode -ge 0 && $newmode -le 4 ]]
|
||||
then
|
||||
if [ $newmode -eq 1 ]
|
||||
then
|
||||
sudo $pythonbin $rtcdaemonscript GETBATTERY
|
||||
#if [ -f "$UPSSTATUSFILE" ]
|
||||
#then
|
||||
# cat $UPSSTATUSFILE
|
||||
#else
|
||||
# echo "Unable to retrieve status"
|
||||
#fi
|
||||
elif [ $newmode -eq 2 ]
|
||||
then
|
||||
$rtcconfigscript "argonupsrtc"
|
||||
#TMPTIMESTR=`date +"%Y%d%m%H%M%S"`
|
||||
#TMPDATASTR=`date +"%Y %m %d %H %M %S"`
|
||||
|
||||
#echo "$TMPTIMESTR" > $UPSCMDFILE
|
||||
#echo "3 $TMPDATASTR" >> $UPSCMDFILE
|
||||
elif [ $newmode -eq 3 ]
|
||||
then
|
||||
# Start installation
|
||||
if [ ! -d "$INSTALLATIONFOLDER/ups" ]
|
||||
then
|
||||
sudo mkdir $INSTALLATIONFOLDER/ups
|
||||
fi
|
||||
|
||||
|
||||
rtcconfigfile=/etc/argonupsrtc.conf
|
||||
# Generate default RTC config file if non-existent
|
||||
if [ ! -f $rtcconfigfile ]; then
|
||||
sudo touch $rtcconfigfile
|
||||
sudo chmod 666 $rtcconfigfile
|
||||
|
||||
echo '#' >> $rtcconfigfile
|
||||
echo '# Argon RTC Configuration' >> $rtcconfigfile
|
||||
echo '#' >> $rtcconfigfile
|
||||
fi
|
||||
|
||||
for iconfile in battery_0 battery_2 battery_4 battery_charging battery_unknown battery_1 battery_3 battery_alert battery_plug
|
||||
do
|
||||
sudo wget $ARGONDOWNLOADSERVER/ups/${iconfile}.png -O $INSTALLATIONFOLDER/ups/${iconfile}.png --quiet
|
||||
done
|
||||
|
||||
sudo wget $ARGONDOWNLOADSERVER/ups/upsimg.tar.gz -O $INSTALLATIONFOLDER/ups/upsimg.tar.gz --quiet
|
||||
sudo tar xfz $INSTALLATIONFOLDER/ups/upsimg.tar.gz -C $INSTALLATIONFOLDER/ups/
|
||||
sudo rm -Rf $INSTALLATIONFOLDER/ups/upsimg.tar.gz
|
||||
|
||||
# Desktop Icon
|
||||
destfoldername=$USERNAME
|
||||
if [ -z "$destfoldername" ]
|
||||
then
|
||||
destfoldername=$USER
|
||||
fi
|
||||
if [ -z "$destfoldername" ]
|
||||
then
|
||||
destfoldername="pi"
|
||||
fi
|
||||
|
||||
shortcutfile="/home/$destfoldername/Desktop/argonone-ups.desktop"
|
||||
if [ -d "/home/$destfoldername/Desktop" ]
|
||||
then
|
||||
terminalcmd="lxterminal --working-directory=/home/$destfoldername/ -t"
|
||||
if [ -f "/home/$destfoldername/.twisteros.twid" ]
|
||||
then
|
||||
terminalcmd="xfce4-terminal --default-working-directory=/home/$destfoldername/ -T"
|
||||
fi
|
||||
|
||||
echo "[Desktop Entry]" > $shortcutfile
|
||||
echo "Name=Argon UPS" >> $shortcutfile
|
||||
echo "Comment=Argon UPS" >> $shortcutfile
|
||||
echo "Icon=/etc/argon/ups/loading_0.png" >> $shortcutfile
|
||||
echo 'Exec='$terminalcmd' "Argon UPS" -e "'$rtcconfigscript' argonupsrtc"' >> $shortcutfile
|
||||
echo "Type=Application" >> $shortcutfile
|
||||
echo "Encoding=UTF-8" >> $shortcutfile
|
||||
echo "Terminal=false" >> $shortcutfile
|
||||
echo "Categories=None;" >> $shortcutfile
|
||||
chmod 755 $shortcutfile
|
||||
fi
|
||||
|
||||
# Stopped using default battery indicator
|
||||
## Build Kernel Module
|
||||
#sourcecodefolder=$INSTALLATIONFOLDER/tmp
|
||||
#buildfolder=$sourcecodefolder/build
|
||||
#if [ -d $sourcecodefolder ]
|
||||
#then
|
||||
# sudo rm -rf $sourcecodefolder
|
||||
#fi
|
||||
#if [ "$CHECKPLATFORM" = "Ubuntu" ]
|
||||
#then
|
||||
# sudo apt-get install build-essential
|
||||
#fi
|
||||
#sudo mkdir -p $buildfolder
|
||||
#sudo chmod -R 755 $buildfolder
|
||||
|
||||
#FILELIST="COPYING Makefile argonbatteryicon.c"
|
||||
#for fname in $FILELIST
|
||||
#do
|
||||
# sudo wget $ARGONDOWNLOADSERVER/modules/argonbatteryicon/$fname -O $buildfolder/#$fname --quiet
|
||||
#done
|
||||
|
||||
## Start Build
|
||||
#cd $buildfolder/
|
||||
#sudo make
|
||||
#sudo cp "$buildfolder/argonbatteryicon.ko" "$INSTALLATIONFOLDER/ups/"
|
||||
|
||||
## Cleanup
|
||||
#cd $INSTALLATIONFOLDER/
|
||||
#sudo rm -Rf "$sourcecodefolder"
|
||||
|
||||
sudo wget $ARGONDOWNLOADSERVER/scripts/argononeupsd.py -O "$upsdaemonscript" --quiet
|
||||
sudo wget $ARGONDOWNLOADSERVER/scripts/argononeupsd.service -O "$daemonupsservice" --quiet
|
||||
sudo chmod 666 $daemonupsservice
|
||||
#echo "User=$destfoldername" >> "$daemonupsservice"
|
||||
#echo "Group=$destfoldername" >> "$daemonupsservice"
|
||||
|
||||
sudo chmod 644 $daemonupsservice
|
||||
|
||||
sudo wget $ARGONDOWNLOADSERVER/scripts/argoneon-rtcconfig.sh -O $rtcconfigscript --quiet
|
||||
sudo chmod 755 $rtcconfigscript
|
||||
|
||||
sudo wget $ARGONDOWNLOADSERVER/scripts/argonrtc.py -O $INSTALLATIONFOLDER/argonrtc.py --quiet
|
||||
sudo wget $ARGONDOWNLOADSERVER/scripts/argonupsrtcd.py -O "$rtcdaemonscript" --quiet
|
||||
sudo wget $ARGONDOWNLOADSERVER/scripts/argonupsrtcd.service -O "$daemonrtcservice" --quiet
|
||||
sudo chmod 644 $daemonrtcservice
|
||||
|
||||
if [ $requireinstall -eq 1 ]
|
||||
then
|
||||
requireinstall=0
|
||||
sudo systemctl enable "$daemonname.service"
|
||||
sudo systemctl start "$daemonname.service"
|
||||
|
||||
sudo systemctl enable "$rtcdaemonname.service"
|
||||
sudo systemctl start "$rtcdaemonname.service"
|
||||
else
|
||||
sudo systemctl restart "$daemonname.service"
|
||||
sudo systemctl restart "$rtcdaemonname.service"
|
||||
loopflag=0
|
||||
fi
|
||||
# Serial I/O is here
|
||||
sudo systemctl restart argononed.service
|
||||
elif [ $newmode -eq 4 ]
|
||||
then
|
||||
sudo systemctl stop "$daemonname.service"
|
||||
sudo systemctl disable "$daemonname.service"
|
||||
sudo rm $daemonupsservice
|
||||
sudo rm $upsdaemonscript
|
||||
|
||||
sudo systemctl stop "$rtcdaemonname.service"
|
||||
sudo systemctl disable "$rtcdaemonname.service"
|
||||
sudo rm $daemonrtcservice
|
||||
sudo rm $rtcdaemonscript
|
||||
|
||||
sudo rm -R -f $INSTALLATIONFOLDER/ups
|
||||
|
||||
echo "Uninstall Completed"
|
||||
loopflag=0
|
||||
else
|
||||
echo "Cancelled"
|
||||
loopflag=0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
|
600
source/scripts/argononed.py
Normal file
600
source/scripts/argononed.py
Normal file
@ -0,0 +1,600 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
#
|
||||
# This script set fan speed and monitor power button events.
|
||||
#
|
||||
# Fan Speed is set by sending 0 to 100 to the MCU (Micro Controller Unit)
|
||||
# The values will be interpreted as the percentage of fan speed, 100% being maximum
|
||||
#
|
||||
# Power button events are sent as a pulse signal to BCM Pin 4 (BOARD P7)
|
||||
# A pulse width of 20-30ms indicates reboot request (double-tap)
|
||||
# A pulse width of 40-50ms indicates shutdown request (hold and release after 3 secs)
|
||||
#
|
||||
# Additional comments are found in each function below
|
||||
#
|
||||
# Standard Deployment/Triggers:
|
||||
# * Raspbian, OSMC: Runs as service via /lib/systemd/system/argononed.service
|
||||
# * lakka, libreelec: Runs as service via /storage/.config/system.d/argononed.service
|
||||
# * recalbox: Runs as service via /etc/init.d/
|
||||
#
|
||||
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
from threading import Thread
|
||||
from queue import Queue
|
||||
|
||||
sys.path.append("/etc/argon/")
|
||||
from argonsysinfo import *
|
||||
from argonregister import *
|
||||
from argonpowerbutton import *
|
||||
|
||||
# Initialize I2C Bus
|
||||
bus = argonregister_initializebusobj()
|
||||
|
||||
OLED_ENABLED=False
|
||||
|
||||
if os.path.exists("/etc/argon/argoneonoled.py"):
|
||||
import datetime
|
||||
from argoneonoled import *
|
||||
OLED_ENABLED=True
|
||||
|
||||
OLED_CONFIGFILE = "/etc/argoneonoled.conf"
|
||||
UNIT_CONFIGFILE = "/etc/argonunits.conf"
|
||||
|
||||
# This function converts the corresponding fanspeed for the given temperature
|
||||
# The configuration data is a list of strings in the form "<temperature>=<speed>"
|
||||
|
||||
def get_fanspeed(tempval, configlist):
|
||||
for curconfig in configlist:
|
||||
curpair = curconfig.split("=")
|
||||
tempcfg = float(curpair[0])
|
||||
fancfg = int(float(curpair[1]))
|
||||
if tempval >= tempcfg:
|
||||
if fancfg < 1:
|
||||
return 0
|
||||
elif fancfg < 25:
|
||||
return 25
|
||||
return fancfg
|
||||
return 0
|
||||
|
||||
# This function retrieves the fanspeed configuration list from a file, arranged by temperature
|
||||
# It ignores lines beginning with "#" and checks if the line is a valid temperature-speed pair
|
||||
# The temperature values are formatted to uniform length, so the lines can be sorted properly
|
||||
|
||||
def load_config(fname):
|
||||
newconfig = []
|
||||
try:
|
||||
with open(fname, "r") as fp:
|
||||
for curline in fp:
|
||||
if not curline:
|
||||
continue
|
||||
tmpline = curline.strip()
|
||||
if not tmpline:
|
||||
continue
|
||||
if tmpline[0] == "#":
|
||||
continue
|
||||
tmppair = tmpline.split("=")
|
||||
if len(tmppair) != 2:
|
||||
continue
|
||||
tempval = 0
|
||||
fanval = 0
|
||||
try:
|
||||
tempval = float(tmppair[0])
|
||||
if tempval < 0 or tempval > 100:
|
||||
continue
|
||||
except:
|
||||
continue
|
||||
try:
|
||||
fanval = int(float(tmppair[1]))
|
||||
if fanval < 0 or fanval > 100:
|
||||
continue
|
||||
except:
|
||||
continue
|
||||
newconfig.append( "{:5.1f}={}".format(tempval,fanval))
|
||||
if len(newconfig) > 0:
|
||||
newconfig.sort(reverse=True)
|
||||
except:
|
||||
return []
|
||||
return newconfig
|
||||
|
||||
# Load OLED Config file
|
||||
def load_oledconfig(fname):
|
||||
output={}
|
||||
screenduration=-1
|
||||
screenlist=[]
|
||||
try:
|
||||
with open(fname, "r") as fp:
|
||||
for curline in fp:
|
||||
if not curline:
|
||||
continue
|
||||
tmpline = curline.strip()
|
||||
if not tmpline:
|
||||
continue
|
||||
if tmpline[0] == "#":
|
||||
continue
|
||||
tmppair = tmpline.split("=")
|
||||
if len(tmppair) != 2:
|
||||
continue
|
||||
if tmppair[0] == "switchduration":
|
||||
output['screenduration']=int(tmppair[1])
|
||||
elif tmppair[0] == "screensaver":
|
||||
output['screensaver']=int(tmppair[1])
|
||||
elif tmppair[0] == "screenlist":
|
||||
output['screenlist']=tmppair[1].replace("\"", "").split(" ")
|
||||
elif tmppair[0] == "enabled":
|
||||
output['enabled']=tmppair[1].replace("\"", "")
|
||||
except:
|
||||
return {}
|
||||
return output
|
||||
|
||||
# Load Unit Config file
|
||||
def load_unitconfig(fname):
|
||||
output={"temperature": "C"}
|
||||
try:
|
||||
with open(fname, "r") as fp:
|
||||
for curline in fp:
|
||||
if not curline:
|
||||
continue
|
||||
tmpline = curline.strip()
|
||||
if not tmpline:
|
||||
continue
|
||||
if tmpline[0] == "#":
|
||||
continue
|
||||
tmppair = tmpline.split("=")
|
||||
if len(tmppair) != 2:
|
||||
continue
|
||||
if tmppair[0] == "temperature":
|
||||
output['temperature']=tmppair[1].replace("\"", "")
|
||||
except:
|
||||
return {}
|
||||
return output
|
||||
|
||||
def load_fancpuconfig():
|
||||
fanconfig = ["65=100", "60=55", "55=30"]
|
||||
tmpconfig = load_config("/etc/argononed.conf")
|
||||
if len(tmpconfig) > 0:
|
||||
fanconfig = tmpconfig
|
||||
return fanconfig
|
||||
|
||||
|
||||
def load_fanhddconfig():
|
||||
fanhddconfig = ["50=100", "40=55", "30=30"]
|
||||
fanhddconfigfile = "/etc/argononed-hdd.conf"
|
||||
|
||||
if os.path.isfile(fanhddconfigfile):
|
||||
tmpconfig = load_config(fanhddconfigfile)
|
||||
if len(tmpconfig) > 0:
|
||||
fanhddconfig = tmpconfig
|
||||
else:
|
||||
fanhddconfig = []
|
||||
return fanhddconfig
|
||||
|
||||
# This function is the thread that monitors temperature and sets the fan speed
|
||||
# The value is fed to get_fanspeed to get the new fan speed
|
||||
# To prevent unnecessary fluctuations, lowering fan speed is delayed by 30 seconds
|
||||
#
|
||||
# Location of config file varies based on OS
|
||||
#
|
||||
def temp_check():
|
||||
INITIALSPEEDVAL = 200 # ensures fan speed gets set during initialization (e.g. change settings)
|
||||
argonregsupport = argonregister_checksupport(bus)
|
||||
|
||||
fanconfig = load_fancpuconfig()
|
||||
fanhddconfig = load_fanhddconfig()
|
||||
|
||||
prevspeed=INITIALSPEEDVAL
|
||||
while True:
|
||||
# Speed based on CPU Temp
|
||||
val = argonsysinfo_getcputemp()
|
||||
newspeed = get_fanspeed(val, fanconfig)
|
||||
# Speed based on HDD Temp
|
||||
val = argonsysinfo_getmaxhddtemp()
|
||||
tmpspeed = get_fanspeed(val, fanhddconfig)
|
||||
|
||||
# Use faster fan speed
|
||||
if tmpspeed > newspeed:
|
||||
newspeed = tmpspeed
|
||||
|
||||
if prevspeed == newspeed:
|
||||
time.sleep(30)
|
||||
continue
|
||||
elif newspeed < prevspeed and prevspeed != INITIALSPEEDVAL:
|
||||
# Pause 30s before speed reduction to prevent fluctuations
|
||||
time.sleep(30)
|
||||
prevspeed = newspeed
|
||||
try:
|
||||
if newspeed > 0:
|
||||
# Spin up to prevent issues on older units
|
||||
argonregister_setfanspeed(bus, 100, argonregsupport)
|
||||
# Set fan speed has sleep
|
||||
argonregister_setfanspeed(bus, newspeed, argonregsupport)
|
||||
time.sleep(30)
|
||||
except IOError:
|
||||
time.sleep(60)
|
||||
|
||||
#
|
||||
# This function is the thread that updates OLED
|
||||
#
|
||||
def display_loop(readq):
|
||||
weekdaynamelist = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
|
||||
monthlist = ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"]
|
||||
oledscreenwidth = oled_getmaxX()
|
||||
|
||||
fontwdSml = 6 # Maps to 6x8
|
||||
fontwdReg = 8 # Maps to 8x16
|
||||
stdleftoffset = 54
|
||||
|
||||
temperature="C"
|
||||
tmpconfig=load_unitconfig(UNIT_CONFIGFILE)
|
||||
if "temperature" in tmpconfig:
|
||||
temperature = tmpconfig["temperature"]
|
||||
|
||||
screensavermode = False
|
||||
screensaversec = 120
|
||||
screensaverctr = 0
|
||||
|
||||
screenenabled = ["clock", "ip"]
|
||||
prevscreen = ""
|
||||
curscreen = ""
|
||||
screenid = 0
|
||||
screenjogtime = 0
|
||||
screenjogflag = 0 # start with screenid 0
|
||||
cpuusagelist = []
|
||||
curlist = []
|
||||
|
||||
tmpconfig=load_oledconfig(OLED_CONFIGFILE)
|
||||
|
||||
if "screensaver" in tmpconfig:
|
||||
screensaversec = tmpconfig["screensaver"]
|
||||
if "screenduration" in tmpconfig:
|
||||
screenjogtime = tmpconfig["screenduration"]
|
||||
if "screenlist" in tmpconfig:
|
||||
screenenabled = tmpconfig["screenlist"]
|
||||
|
||||
if "enabled" in tmpconfig:
|
||||
if tmpconfig["enabled"] == "N":
|
||||
screenenabled = []
|
||||
|
||||
while len(screenenabled) > 0:
|
||||
if len(curlist) == 0 and screenjogflag == 1:
|
||||
# Reset Screen Saver
|
||||
screensavermode = False
|
||||
screensaverctr = 0
|
||||
|
||||
# Update screen info
|
||||
screenid = screenid + screenjogflag
|
||||
if screenid >= len(screenenabled):
|
||||
screenid = 0
|
||||
prevscreen = curscreen
|
||||
curscreen = screenenabled[screenid]
|
||||
|
||||
if screenjogtime == 0:
|
||||
# Resets jogflag (if switched manually)
|
||||
screenjogflag = 0
|
||||
else:
|
||||
screenjogflag = 1
|
||||
|
||||
needsUpdate = False
|
||||
if curscreen == "cpu":
|
||||
# CPU Usage
|
||||
if len(curlist) == 0:
|
||||
try:
|
||||
if len(cpuusagelist) == 0:
|
||||
cpuusagelist = argonsysinfo_listcpuusage()
|
||||
curlist = cpuusagelist
|
||||
except:
|
||||
curlist = []
|
||||
if len(curlist) > 0:
|
||||
oled_loadbg("bgcpu")
|
||||
|
||||
# Display List
|
||||
yoffset = 0
|
||||
tmpmax = 4
|
||||
while tmpmax > 0 and len(curlist) > 0:
|
||||
curline = ""
|
||||
tmpitem = curlist.pop(0)
|
||||
curline = tmpitem["title"]+": "+str(tmpitem["value"])+"%"
|
||||
oled_writetext(curline, stdleftoffset, yoffset, fontwdSml)
|
||||
oled_drawfilledrectangle(stdleftoffset, yoffset+12, int((oledscreenwidth-stdleftoffset-4)*tmpitem["value"]/100), 2)
|
||||
tmpmax = tmpmax - 1
|
||||
yoffset = yoffset + 16
|
||||
|
||||
needsUpdate = True
|
||||
else:
|
||||
# Next page due to error/no data
|
||||
screenjogflag = 1
|
||||
elif curscreen == "storage":
|
||||
# Storage Info
|
||||
if len(curlist) == 0:
|
||||
try:
|
||||
tmpobj = argonsysinfo_listhddusage()
|
||||
for curdev in tmpobj:
|
||||
curlist.append({"title": curdev, "value": argonsysinfo_kbstr(tmpobj[curdev]['total']), "usage": int(100*tmpobj[curdev]['used']/tmpobj[curdev]['total']) })
|
||||
#curlist = argonsysinfo_liststoragetotal()
|
||||
except:
|
||||
curlist = []
|
||||
if len(curlist) > 0:
|
||||
oled_loadbg("bgstorage")
|
||||
|
||||
yoffset = 16
|
||||
tmpmax = 3
|
||||
while tmpmax > 0 and len(curlist) > 0:
|
||||
tmpitem = curlist.pop(0)
|
||||
# Right column first, safer to overwrite white space
|
||||
oled_writetextaligned(tmpitem["value"], 77, yoffset, oledscreenwidth-77, 2, fontwdSml)
|
||||
oled_writetextaligned(str(tmpitem["usage"])+"%", 50, yoffset, 74-50, 2, fontwdSml)
|
||||
tmpname = tmpitem["title"]
|
||||
if len(tmpname) > 8:
|
||||
tmpname = tmpname[0:8]
|
||||
oled_writetext(tmpname, 0, yoffset, fontwdSml)
|
||||
|
||||
tmpmax = tmpmax - 1
|
||||
yoffset = yoffset + 16
|
||||
needsUpdate = True
|
||||
else:
|
||||
# Next page due to error/no data
|
||||
screenjogflag = 1
|
||||
|
||||
elif curscreen == "raid":
|
||||
# Raid Info
|
||||
if len(curlist) == 0:
|
||||
try:
|
||||
tmpobj = argonsysinfo_listraid()
|
||||
curlist = tmpobj['raidlist']
|
||||
except:
|
||||
curlist = []
|
||||
if len(curlist) > 0:
|
||||
oled_loadbg("bgraid")
|
||||
tmpitem = curlist.pop(0)
|
||||
oled_writetextaligned(tmpitem["title"], 0, 0, stdleftoffset, 1, fontwdSml)
|
||||
oled_writetextaligned(tmpitem["value"], 0, 8, stdleftoffset, 1, fontwdSml)
|
||||
oled_writetextaligned(argonsysinfo_kbstr(tmpitem["info"]["size"]), 0, 56, stdleftoffset, 1, fontwdSml)
|
||||
|
||||
if len(tmpitem['info']['state']) > 0:
|
||||
oled_writetext( tmpitem['info']['state'], stdleftoffset, 8, fontwdSml )
|
||||
|
||||
if len(tmpitem['info']['rebuildstat']) > 0:
|
||||
oled_writetext("Rebuild:" + tmpitem['info']['rebuildstat'], stdleftoffset, 16, fontwdSml)
|
||||
|
||||
# TODO: May need to use different method for each raid type (i.e. check raidlist['raidlist'][raidctr]['value'])
|
||||
#oled_writetext("Used:"+str(int(100*tmpitem["info"]["used"]/tmpitem["info"]["size"]))+"%", stdleftoffset, 24, fontwdSml)
|
||||
|
||||
|
||||
oled_writetext("Active:"+str(int(tmpitem["info"]["active"]))+"/"+str(int(tmpitem["info"]["devices"])), stdleftoffset, 32, fontwdSml)
|
||||
oled_writetext("Working:"+str(int(tmpitem["info"]["working"]))+"/"+str(int(tmpitem["info"]["devices"])), stdleftoffset, 40, fontwdSml)
|
||||
oled_writetext("Failed:"+str(int(tmpitem["info"]["failed"]))+"/"+str(int(tmpitem["info"]["devices"])), stdleftoffset, 48, fontwdSml)
|
||||
needsUpdate = True
|
||||
else:
|
||||
# Next page due to error/no data
|
||||
screenjogflag = 1
|
||||
|
||||
elif curscreen == "ram":
|
||||
# RAM
|
||||
try:
|
||||
oled_loadbg("bgram")
|
||||
tmpraminfo = argonsysinfo_getram()
|
||||
oled_writetextaligned(tmpraminfo[0], stdleftoffset, 8, oledscreenwidth-stdleftoffset, 1, fontwdReg)
|
||||
oled_writetextaligned("of", stdleftoffset, 24, oledscreenwidth-stdleftoffset, 1, fontwdReg)
|
||||
oled_writetextaligned(tmpraminfo[1], stdleftoffset, 40, oledscreenwidth-stdleftoffset, 1, fontwdReg)
|
||||
needsUpdate = True
|
||||
except:
|
||||
needsUpdate = False
|
||||
# Next page due to error/no data
|
||||
screenjogflag = 1
|
||||
elif curscreen == "temp":
|
||||
# Temp
|
||||
try:
|
||||
oled_loadbg("bgtemp")
|
||||
hddtempctr = 0
|
||||
maxcval = 0
|
||||
mincval = 200
|
||||
|
||||
|
||||
# Get min/max of hdd temp
|
||||
hddtempobj = argonsysinfo_gethddtemp()
|
||||
for curdev in hddtempobj:
|
||||
if hddtempobj[curdev] < mincval:
|
||||
mincval = hddtempobj[curdev]
|
||||
if hddtempobj[curdev] > maxcval:
|
||||
maxcval = hddtempobj[curdev]
|
||||
hddtempctr = hddtempctr + 1
|
||||
|
||||
cpucval = argonsysinfo_getcputemp()
|
||||
if hddtempctr > 0:
|
||||
alltempobj = {"cpu": cpucval,"hdd min": mincval, "hdd max": maxcval}
|
||||
# Update max C val to CPU Temp if necessary
|
||||
if maxcval < cpucval:
|
||||
maxcval = cpucval
|
||||
|
||||
displayrowht = 8
|
||||
displayrow = 8
|
||||
for curdev in alltempobj:
|
||||
if temperature == "C":
|
||||
# Celsius
|
||||
tmpstr = str(alltempobj[curdev])
|
||||
if len(tmpstr) > 4:
|
||||
tmpstr = tmpstr[0:4]
|
||||
else:
|
||||
# Fahrenheit
|
||||
tmpstr = str(32+9*(alltempobj[curdev])/5)
|
||||
if len(tmpstr) > 5:
|
||||
tmpstr = tmpstr[0:5]
|
||||
if len(curdev) <= 3:
|
||||
oled_writetext(curdev.upper()+": "+ tmpstr+ chr(167) +temperature, stdleftoffset, displayrow, fontwdSml)
|
||||
|
||||
else:
|
||||
oled_writetext(curdev.upper()+":", stdleftoffset, displayrow, fontwdSml)
|
||||
|
||||
oled_writetext(" "+ tmpstr+ chr(167) +temperature, stdleftoffset, displayrow+displayrowht, fontwdSml)
|
||||
displayrow = displayrow + displayrowht*2
|
||||
else:
|
||||
maxcval = cpucval
|
||||
if temperature == "C":
|
||||
# Celsius
|
||||
tmpstr = str(cpucval)
|
||||
if len(tmpstr) > 4:
|
||||
tmpstr = tmpstr[0:4]
|
||||
else:
|
||||
# Fahrenheit
|
||||
tmpstr = str(32+9*(cpucval)/5)
|
||||
if len(tmpstr) > 5:
|
||||
tmpstr = tmpstr[0:5]
|
||||
|
||||
oled_writetextaligned(tmpstr+ chr(167) +temperature, stdleftoffset, 24, oledscreenwidth-stdleftoffset, 1, fontwdReg)
|
||||
|
||||
# Temperature Bar: 40C is min, 80C is max
|
||||
maxht = 21
|
||||
barht = int(maxht*(maxcval-40)/40)
|
||||
if barht > maxht:
|
||||
barht = maxht
|
||||
elif barht < 1:
|
||||
barht = 1
|
||||
oled_drawfilledrectangle(24, 20+(maxht-barht), 3, barht, 2)
|
||||
|
||||
|
||||
needsUpdate = True
|
||||
except:
|
||||
needsUpdate = False
|
||||
# Next page due to error/no data
|
||||
screenjogflag = 1
|
||||
elif curscreen == "ip":
|
||||
# IP Address
|
||||
try:
|
||||
oled_loadbg("bgip")
|
||||
oled_writetextaligned(argonsysinfo_getip(), 0, 8, oledscreenwidth, 1, fontwdReg)
|
||||
needsUpdate = True
|
||||
except:
|
||||
needsUpdate = False
|
||||
# Next page due to error/no data
|
||||
screenjogflag = 1
|
||||
elif curscreen == "logo1v5":
|
||||
# Logo
|
||||
try:
|
||||
oled_loadbg("logo1v5")
|
||||
needsUpdate = True
|
||||
except:
|
||||
needsUpdate = False
|
||||
# Next page due to error/no data
|
||||
screenjogflag = 1
|
||||
else:
|
||||
try:
|
||||
oled_loadbg("bgtime")
|
||||
# Date and Time HH:MM
|
||||
curtime = datetime.datetime.now()
|
||||
|
||||
# Month/Day
|
||||
outstr = str(curtime.day).strip()
|
||||
if len(outstr) < 2:
|
||||
outstr = " "+outstr
|
||||
outstr = monthlist[curtime.month-1]+outstr
|
||||
oled_writetextaligned(outstr, stdleftoffset, 8, oledscreenwidth-stdleftoffset, 1, fontwdReg)
|
||||
|
||||
# Day of Week
|
||||
oled_writetextaligned(weekdaynamelist[curtime.weekday()], stdleftoffset, 24, oledscreenwidth-stdleftoffset, 1, fontwdReg)
|
||||
|
||||
# Time
|
||||
outstr = str(curtime.minute).strip()
|
||||
if len(outstr) < 2:
|
||||
outstr = "0"+outstr
|
||||
outstr = str(curtime.hour)+":"+outstr
|
||||
if len(outstr) < 5:
|
||||
outstr = "0"+outstr
|
||||
oled_writetextaligned(outstr, stdleftoffset, 40, oledscreenwidth-stdleftoffset, 1, fontwdReg)
|
||||
|
||||
needsUpdate = True
|
||||
except:
|
||||
needsUpdate = False
|
||||
# Next page due to error/no data
|
||||
screenjogflag = 1
|
||||
|
||||
if needsUpdate == True:
|
||||
if screensavermode == False:
|
||||
# Update screen if not screen saver mode
|
||||
oled_power(True)
|
||||
oled_flushimage(prevscreen != curscreen)
|
||||
oled_reset()
|
||||
|
||||
timeoutcounter = 0
|
||||
while timeoutcounter<screenjogtime or screenjogtime == 0:
|
||||
qdata = ""
|
||||
if readq.empty() == False:
|
||||
qdata = readq.get()
|
||||
|
||||
if qdata == "OLEDSWITCH":
|
||||
# Trigger screen switch
|
||||
screenjogflag = 1
|
||||
# Reset Screen Saver
|
||||
screensavermode = False
|
||||
screensaverctr = 0
|
||||
|
||||
break
|
||||
elif qdata == "OLEDSTOP":
|
||||
# End OLED Thread
|
||||
display_defaultimg()
|
||||
return
|
||||
else:
|
||||
screensaverctr = screensaverctr + 1
|
||||
if screensaversec <= screensaverctr and screensavermode == False:
|
||||
screensavermode = True
|
||||
oled_fill(0)
|
||||
oled_reset()
|
||||
oled_power(False)
|
||||
|
||||
if timeoutcounter == 0:
|
||||
# Use 1 sec sleep get CPU usage
|
||||
cpuusagelist = argonsysinfo_listcpuusage(1)
|
||||
else:
|
||||
time.sleep(1)
|
||||
|
||||
timeoutcounter = timeoutcounter + 1
|
||||
if timeoutcounter >= 60 and screensavermode == False:
|
||||
# Refresh data every minute, unless screensaver got triggered
|
||||
screenjogflag = 0
|
||||
break
|
||||
display_defaultimg()
|
||||
|
||||
def display_defaultimg():
|
||||
# Load default image
|
||||
#oled_power(True)
|
||||
#oled_loadbg("bgdefault")
|
||||
#oled_flushimage()
|
||||
oled_fill(0)
|
||||
oled_reset()
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
cmd = sys.argv[1].upper()
|
||||
if cmd == "SHUTDOWN":
|
||||
# Signal poweroff
|
||||
argonregister_signalpoweroff(bus)
|
||||
|
||||
elif cmd == "FANOFF":
|
||||
# Turn off fan
|
||||
argonregister_setfanspeed(bus,0)
|
||||
|
||||
if OLED_ENABLED == True:
|
||||
display_defaultimg()
|
||||
|
||||
elif cmd == "SERVICE":
|
||||
# Starts the power button and temperature monitor threads
|
||||
try:
|
||||
ipcq = Queue()
|
||||
if len(sys.argv) > 2:
|
||||
cmd = sys.argv[2].upper()
|
||||
if cmd == "OLEDSWITCH":
|
||||
t1 = Thread(target = argonpowerbutton_monitorswitch, args =(ipcq, ))
|
||||
else:
|
||||
t1 = Thread(target = argonpowerbutton_monitor, args =(ipcq, ))
|
||||
|
||||
t2 = Thread(target = temp_check)
|
||||
if OLED_ENABLED == True:
|
||||
t3 = Thread(target = display_loop, args =(ipcq, ))
|
||||
|
||||
t1.start()
|
||||
t2.start()
|
||||
if OLED_ENABLED == True:
|
||||
t3.start()
|
||||
|
||||
ipcq.join()
|
||||
except Exception:
|
||||
sys.exit(1)
|
10
source/scripts/argononed.service
Normal file
10
source/scripts/argononed.service
Normal file
@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Argon One Fan and Button Service
|
||||
After=multi-user.target
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
RemainAfterExit=true
|
||||
ExecStart=/usr/bin/python3 /etc/argon/argononed.py SERVICE
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
333
source/scripts/argononeoled.py
Normal file
333
source/scripts/argononeoled.py
Normal file
@ -0,0 +1,333 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from luma.core.interface.serial import i2c
|
||||
from luma.oled.device import ssd1306
|
||||
from PIL import Image
|
||||
|
||||
import sys
|
||||
import datetime
|
||||
import math
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
# Initialize I2C Bus
|
||||
import smbus
|
||||
|
||||
oledport=1
|
||||
|
||||
try:
|
||||
bus=smbus.SMBus(1)
|
||||
except Exception:
|
||||
try:
|
||||
oledport=0
|
||||
# Older version
|
||||
bus=smbus.SMBus(0)
|
||||
except Exception:
|
||||
print("Unable to detect i2c")
|
||||
bus=None
|
||||
|
||||
|
||||
ADDR_OLED=0x3c
|
||||
OLED_WD=1
|
||||
OLED_HT=1
|
||||
oled_device=None
|
||||
try:
|
||||
oled_device=ssd1306(i2c(port=oledport, address=ADDR_OLED))
|
||||
|
||||
OLED_WD=oled_device.bounding_box[2]+1
|
||||
OLED_HT=oled_device.bounding_box[3]+1
|
||||
except Exception:
|
||||
print("Unable to initialize OLED")
|
||||
bus=None
|
||||
|
||||
OLED_NUMFONTCHAR=256
|
||||
|
||||
OLED_BUFFERIZE = ((OLED_WD*OLED_HT)>>3)
|
||||
oled_imagebuffer = [0] * OLED_BUFFERIZE
|
||||
|
||||
|
||||
def oled_getmaxY():
|
||||
return OLED_HT
|
||||
|
||||
def oled_getmaxX():
|
||||
return OLED_WD
|
||||
|
||||
def oled_loadbg(bgname):
|
||||
if bgname == "bgblack":
|
||||
oled_clearbuffer()
|
||||
return
|
||||
elif bgname == "bgwhite":
|
||||
oled_clearbuffer(1)
|
||||
return
|
||||
try:
|
||||
file = open("/etc/argon/oled/"+bgname+".bin", "rb")
|
||||
bgbytes = list(file.read())
|
||||
file.close()
|
||||
ctr = len(bgbytes)
|
||||
if ctr == OLED_BUFFERIZE:
|
||||
oled_imagebuffer[:] = bgbytes
|
||||
elif ctr > OLED_BUFFERIZE:
|
||||
oled_imagebuffer[:] = bgbytes[0:OLED_BUFFERIZE]
|
||||
else:
|
||||
oled_imagebuffer[0:ctr] = bgbytes
|
||||
# Clear the rest of the buffer
|
||||
while ctr < OLED_BUFFERIZE:
|
||||
oled_imagebuffer[ctr] = 0
|
||||
ctr=ctr+1
|
||||
except FileNotFoundError:
|
||||
oled_clearbuffer()
|
||||
|
||||
|
||||
def oled_clearbuffer(value = 0):
|
||||
if value != 0:
|
||||
value = 0xff
|
||||
ctr = 0
|
||||
while ctr < OLED_BUFFERIZE:
|
||||
oled_imagebuffer[ctr] = value
|
||||
ctr=ctr+1
|
||||
|
||||
def oled_writebyterow(x,y,bytevalue, mode = 0):
|
||||
bufferoffset = OLED_WD*(y>>3) + x
|
||||
if mode == 0:
|
||||
oled_imagebuffer[bufferoffset] = bytevalue
|
||||
elif mode == 1:
|
||||
oled_imagebuffer[bufferoffset] = bytevalue^oled_imagebuffer[bufferoffset]
|
||||
else:
|
||||
oled_imagebuffer[bufferoffset] = bytevalue|oled_imagebuffer[bufferoffset]
|
||||
|
||||
|
||||
def oled_writebuffer(x,y,value, mode = 0):
|
||||
|
||||
yoffset = y>>3
|
||||
yshift = y&0x7
|
||||
ybit = (1<<yshift)
|
||||
|
||||
ymask = 0xFF^ybit
|
||||
|
||||
if value != 0:
|
||||
value = ybit
|
||||
|
||||
bufferoffset = OLED_WD*yoffset + x
|
||||
|
||||
curval = oled_imagebuffer[bufferoffset]
|
||||
if mode & 1:
|
||||
oled_imagebuffer[bufferoffset] = curval^value
|
||||
else:
|
||||
oled_imagebuffer[bufferoffset] = curval&ymask|value
|
||||
|
||||
|
||||
def oled_fill(value):
|
||||
oled_clearbuffer(value)
|
||||
oled_flushimage()
|
||||
|
||||
|
||||
def oled_flushimage(hidescreen = True):
|
||||
if bus is None:
|
||||
return
|
||||
if hidescreen == True:
|
||||
# Reset/Hide screen
|
||||
oled_power(False)
|
||||
|
||||
tmplist = [0]*OLED_BUFFERIZE
|
||||
|
||||
# Each byte = 1 col x 8 rows
|
||||
|
||||
ymask = 0
|
||||
yidx = 0
|
||||
xmask = 0
|
||||
xidx = 0
|
||||
outbyte = 0
|
||||
srcidx = 0
|
||||
outoffsetidx = 0
|
||||
outyoffset = 0
|
||||
xoffset = 0
|
||||
while srcidx < OLED_BUFFERIZE:
|
||||
# OLED_WDx8 pixels at a time, y in reverse bit order
|
||||
outyoffset = 0
|
||||
yidx = 0
|
||||
ymask = 1
|
||||
while yidx < 8:
|
||||
|
||||
outoffsetidx = 0
|
||||
outbyte = 0
|
||||
xmask = 0x80
|
||||
xidx = 0
|
||||
|
||||
xoffset = 0
|
||||
while xoffset < OLED_WD:
|
||||
if oled_imagebuffer[srcidx+xoffset] & ymask:
|
||||
outbyte = outbyte | xmask
|
||||
xmask = xmask >> 1
|
||||
xidx = xidx + 1
|
||||
if xidx >= 8:
|
||||
tmplist[srcidx+outoffsetidx + outyoffset] = outbyte
|
||||
xmask = 0x80
|
||||
xidx = 0
|
||||
outbyte = 0
|
||||
outoffsetidx = outoffsetidx + 1
|
||||
|
||||
xoffset = xoffset + 1
|
||||
|
||||
outyoffset = outyoffset + (OLED_WD>>3)
|
||||
yidx = yidx + 1
|
||||
ymask = ymask << 1
|
||||
|
||||
srcidx = srcidx + OLED_WD
|
||||
|
||||
oled_device.display(Image.frombytes("1", [OLED_WD, OLED_HT], bytes(tmplist)))
|
||||
|
||||
if hidescreen == True:
|
||||
# Display
|
||||
oled_power(True)
|
||||
|
||||
|
||||
|
||||
def oled_drawfilledrectangle(x, y, wd, ht, mode = 0):
|
||||
ymax = y + ht
|
||||
cury = y&0xF8
|
||||
|
||||
xmax = x + wd
|
||||
curx = x
|
||||
if ((y & 0x7)) != 0:
|
||||
yshift = y&0x7
|
||||
bytevalue = (0xFF<<yshift)&0xFF
|
||||
|
||||
# If 8 no additional masking needed
|
||||
if ymax-cury < 8:
|
||||
yshift = 8-((ymax-cury)&0x7)
|
||||
bytevalue = bytevalue & (0xFF>>yshift)
|
||||
|
||||
while curx < xmax:
|
||||
oled_writebyterow(curx,cury,bytevalue, mode)
|
||||
curx = curx + 1
|
||||
cury = cury + 8
|
||||
# Draw 8 rows at a time when possible
|
||||
while cury + 8 < ymax:
|
||||
curx = x
|
||||
while curx < xmax:
|
||||
oled_writebyterow(curx,cury,0xFF, mode)
|
||||
curx = curx + 1
|
||||
cury = cury + 8
|
||||
|
||||
if cury < ymax:
|
||||
yshift = 8-((ymax-cury)&0x7)
|
||||
bytevalue = (0xFF>>yshift)
|
||||
|
||||
curx = x
|
||||
while curx < xmax:
|
||||
oled_writebyterow(curx,cury,bytevalue, mode)
|
||||
curx = curx + 1
|
||||
|
||||
|
||||
def oled_writetextaligned(textdata, x, y, boxwidth, alignmode, charwd = 6, mode = 0):
|
||||
leftoffset = 0
|
||||
if alignmode == 1:
|
||||
# Centered
|
||||
leftoffset = (boxwidth-len(textdata)*charwd)>>1
|
||||
elif alignmode == 2:
|
||||
# Right aligned
|
||||
leftoffset = (boxwidth-len(textdata)*charwd)
|
||||
|
||||
oled_writetext(textdata, x+leftoffset, y, charwd, mode)
|
||||
|
||||
|
||||
def oled_writetext(textdata, x, y, charwd = 6, mode = 0):
|
||||
if charwd < 6:
|
||||
charwd = 6
|
||||
|
||||
charht = int((charwd<<3)/6)
|
||||
if charht & 0x7:
|
||||
charht = (charht&0xF8) + 8
|
||||
|
||||
try:
|
||||
file = open("/etc/argon/oled/font"+str(charht)+"x"+str(charwd)+".bin", "rb")
|
||||
fontbytes = list(file.read())
|
||||
file.close()
|
||||
except FileNotFoundError:
|
||||
try:
|
||||
# Default to smallest
|
||||
file = open("/etc/argon/oled/font8x6.bin", "rb")
|
||||
fontbytes = list(file.read())
|
||||
file.close()
|
||||
except FileNotFoundError:
|
||||
return
|
||||
|
||||
if ((y & 0x7)) == 0:
|
||||
# Use optimized loading
|
||||
oled_fastwritetext(textdata, x, y, charht, charwd, fontbytes, mode)
|
||||
return
|
||||
|
||||
numfontrow = charht>>3
|
||||
ctr = 0
|
||||
while ctr < len(textdata):
|
||||
fontoffset = ord(textdata[ctr])*charwd
|
||||
fontcol = 0
|
||||
while fontcol < charwd and x < OLED_WD:
|
||||
fontrow = 0
|
||||
row = y
|
||||
while fontrow < numfontrow and row < OLED_HT and x >= 0:
|
||||
curbit = 0x80
|
||||
curbyte = (fontbytes[fontoffset + fontcol + (OLED_NUMFONTCHAR*charwd*fontrow)])
|
||||
subrow = 0
|
||||
while subrow < 8 and row < OLED_HT:
|
||||
value = 0
|
||||
if (curbyte&curbit) != 0:
|
||||
value = 1
|
||||
oled_writebuffer(x,row,value, mode)
|
||||
curbit = curbit >> 1
|
||||
row = row + 1
|
||||
subrow = subrow + 1
|
||||
fontrow = fontrow + 1
|
||||
fontcol = fontcol + 1
|
||||
x = x + 1
|
||||
ctr = ctr + 1
|
||||
|
||||
def oled_fastwritetext(textdata, x, y, charht, charwd, fontbytes, mode = 0):
|
||||
|
||||
numfontrow = charht>>3
|
||||
ctr = 0
|
||||
while ctr < len(textdata):
|
||||
fontoffset = ord(textdata[ctr])*charwd
|
||||
fontcol = 0
|
||||
while fontcol < charwd and x < OLED_WD:
|
||||
fontrow = 0
|
||||
row = y&0xF8
|
||||
while fontrow < numfontrow and row < OLED_HT and x >= 0:
|
||||
curbyte = (fontbytes[fontoffset + fontcol + (OLED_NUMFONTCHAR*charwd*fontrow)])
|
||||
oled_writebyterow(x,row,curbyte, mode)
|
||||
fontrow = fontrow + 1
|
||||
row = row + 8
|
||||
fontcol = fontcol + 1
|
||||
x = x + 1
|
||||
ctr = ctr + 1
|
||||
return
|
||||
|
||||
|
||||
def oled_power(turnon = True):
|
||||
if bus is None:
|
||||
return
|
||||
try:
|
||||
if turnon == True:
|
||||
oled_device.show()
|
||||
else:
|
||||
oled_device.hide()
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
def oled_inverse(enable = True):
|
||||
# Not supported?
|
||||
return
|
||||
|
||||
|
||||
def oled_fullwhite(enable = True):
|
||||
# Not supported?
|
||||
return
|
||||
|
||||
|
||||
|
||||
def oled_reset():
|
||||
return
|
||||
|
||||
|
10
source/scripts/argononeoledd.service
Normal file
10
source/scripts/argononeoledd.service
Normal file
@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Argon One Fan and Button Service
|
||||
After=multi-user.target
|
||||
[Service]
|
||||
Type=simple
|
||||
Restart=always
|
||||
RemainAfterExit=true
|
||||
ExecStart=/usr/bin/python3 /etc/argon/argononed.py SERVICE OLEDSWITCH
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
89
source/scripts/argonpowerbutton-libgpiod.py
Normal file
89
source/scripts/argonpowerbutton-libgpiod.py
Normal file
@ -0,0 +1,89 @@
|
||||
|
||||
# For Libreelec/Lakka, note that we need to add system paths
|
||||
# import sys
|
||||
# sys.path.append('/storage/.kodi/addons/virtual.rpi-tools/lib')
|
||||
import gpiod
|
||||
import os
|
||||
import time
|
||||
|
||||
# This function is the thread that monitors activity in our shutdown pin
|
||||
# The pulse width is measured, and the corresponding shell command will be issued
|
||||
|
||||
def argonpowerbutton_monitor(writeq):
|
||||
|
||||
try:
|
||||
# Reference https://github.com/brgl/libgpiod/blob/master/bindings/python/examples/gpiomon.py
|
||||
|
||||
# Pin Assignments
|
||||
LINE_SHUTDOWN=4
|
||||
try:
|
||||
# Pi5 mapping
|
||||
chip = gpiod.Chip('4')
|
||||
except Exception as gpioerr:
|
||||
# Old mapping
|
||||
chip = gpiod.Chip('0')
|
||||
|
||||
lineobj = chip.get_line(LINE_SHUTDOWN)
|
||||
lineobj.request(consumer="argon", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
while True:
|
||||
hasevent = lineobj.event_wait(10)
|
||||
if hasevent:
|
||||
pulsetime = 1
|
||||
eventdata = lineobj.event_read()
|
||||
if eventdata.type == gpiod.LineEvent.RISING_EDGE:
|
||||
# Time pulse data
|
||||
while lineobj.get_value() == 1:
|
||||
time.sleep(0.01)
|
||||
pulsetime += 1
|
||||
|
||||
if pulsetime >=2 and pulsetime <=3:
|
||||
# Testing
|
||||
#writeq.put("OLEDSWITCH")
|
||||
writeq.put("OLEDSTOP")
|
||||
os.system("reboot")
|
||||
break
|
||||
elif pulsetime >=4 and pulsetime <=5:
|
||||
writeq.put("OLEDSTOP")
|
||||
os.system("shutdown now -h")
|
||||
break
|
||||
elif pulsetime >=6 and pulsetime <=7:
|
||||
writeq.put("OLEDSWITCH")
|
||||
lineobj.release()
|
||||
chip.close()
|
||||
except Exception:
|
||||
writeq.put("ERROR")
|
||||
|
||||
|
||||
def argonpowerbutton_monitorswitch(writeq):
|
||||
|
||||
try:
|
||||
# Reference https://github.com/brgl/libgpiod/blob/master/bindings/python/examples/gpiomon.py
|
||||
|
||||
# Pin Assignments
|
||||
LINE_SHUTDOWN=4
|
||||
try:
|
||||
# Pi5 mapping
|
||||
chip = gpiod.Chip('4')
|
||||
except Exception as gpioerr:
|
||||
# Old mapping
|
||||
chip = gpiod.Chip('0')
|
||||
|
||||
lineobj = chip.get_line(LINE_SHUTDOWN)
|
||||
lineobj.request(consumer="argon", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||
while True:
|
||||
hasevent = lineobj.event_wait(10)
|
||||
if hasevent:
|
||||
pulsetime = 1
|
||||
eventdata = lineobj.event_read()
|
||||
if eventdata.type == gpiod.LineEvent.RISING_EDGE:
|
||||
# Time pulse data
|
||||
while lineobj.get_value() == 1:
|
||||
time.sleep(0.01)
|
||||
pulsetime += 1
|
||||
|
||||
if pulsetime >= 10:
|
||||
writeq.put("OLEDSWITCH")
|
||||
lineobj.release()
|
||||
chip.close()
|
||||
except Exception:
|
||||
writeq.put("ERROR")
|
66
source/scripts/argonpowerbutton-rpigpio.py
Normal file
66
source/scripts/argonpowerbutton-rpigpio.py
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
# For Libreelec/Lakka, note that we need to add system paths
|
||||
# import sys
|
||||
# sys.path.append('/storage/.kodi/addons/virtual.rpi-tools/lib')
|
||||
import RPi.GPIO as GPIO
|
||||
import os
|
||||
import time
|
||||
|
||||
# This function is the thread that monitors activity in our shutdown pin
|
||||
# The pulse width is measured, and the corresponding shell command will be issued
|
||||
|
||||
def argonpowerbutton_monitor(writeq):
|
||||
try:
|
||||
# Pin Assignments
|
||||
PIN_SHUTDOWN=4
|
||||
|
||||
GPIO.setwarnings(False)
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(PIN_SHUTDOWN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
|
||||
while True:
|
||||
pulsetime = 1
|
||||
GPIO.wait_for_edge(PIN_SHUTDOWN, GPIO.RISING)
|
||||
time.sleep(0.01)
|
||||
while GPIO.input(PIN_SHUTDOWN) == GPIO.HIGH:
|
||||
time.sleep(0.01)
|
||||
pulsetime += 1
|
||||
if pulsetime >=2 and pulsetime <=3:
|
||||
# Testing
|
||||
#writeq.put("OLEDSWITCH")
|
||||
writeq.put("OLEDSTOP")
|
||||
os.system("reboot")
|
||||
break
|
||||
elif pulsetime >=4 and pulsetime <=5:
|
||||
writeq.put("OLEDSTOP")
|
||||
os.system("shutdown now -h")
|
||||
break
|
||||
elif pulsetime >=6 and pulsetime <=7:
|
||||
writeq.put("OLEDSWITCH")
|
||||
except Exception:
|
||||
writeq.put("ERROR")
|
||||
GPIO.cleanup()
|
||||
|
||||
|
||||
|
||||
def argonpowerbutton_monitorswitch(writeq):
|
||||
try:
|
||||
# Pin Assignments
|
||||
PIN_SHUTDOWN=4
|
||||
|
||||
GPIO.setwarnings(False)
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(PIN_SHUTDOWN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
|
||||
while True:
|
||||
pulsetime = 1
|
||||
GPIO.wait_for_edge(PIN_SHUTDOWN, GPIO.RISING)
|
||||
time.sleep(0.01)
|
||||
while GPIO.input(PIN_SHUTDOWN) == GPIO.HIGH:
|
||||
time.sleep(0.01)
|
||||
pulsetime += 1
|
||||
if pulsetime >= 10:
|
||||
writeq.put("OLEDSWITCH")
|
||||
except Exception:
|
||||
writeq.put("ERROR")
|
||||
GPIO.cleanup()
|
74
source/scripts/argonregister-v1.py
Normal file
74
source/scripts/argonregister-v1.py
Normal file
@ -0,0 +1,74 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
#
|
||||
# Argon Register Helper methods
|
||||
# Same as argonregister, but no support for new register commands
|
||||
#
|
||||
|
||||
import time
|
||||
import smbus
|
||||
|
||||
# I2C Addresses
|
||||
ADDR_ARGONONEFAN=0x1a
|
||||
ADDR_ARGONONEREG=ADDR_ARGONONEFAN
|
||||
|
||||
# ARGONONEREG Addresses
|
||||
ADDR_ARGONONEREG_DUTYCYCLE=0x80
|
||||
ADDR_ARGONONEREG_FW=0x81
|
||||
ADDR_ARGONONEREG_IR=0x82
|
||||
ADDR_ARGONONEREG_CTRL=0x86
|
||||
|
||||
# Initialize bus
|
||||
def argonregister_initializebusobj():
|
||||
try:
|
||||
return smbus.SMBus(1)
|
||||
except Exception:
|
||||
try:
|
||||
# Older version
|
||||
return smbus.SMBus(0)
|
||||
except Exception:
|
||||
print("Unable to detect i2c")
|
||||
return None
|
||||
|
||||
|
||||
# Checks if the FW supports control registers
|
||||
def argonregister_checksupport(busobj):
|
||||
return False
|
||||
|
||||
def argonregister_getbyte(busobj, address):
|
||||
if busobj is None:
|
||||
return 0
|
||||
return busobj.read_byte_data(ADDR_ARGONONEREG, address)
|
||||
|
||||
def argonregister_setbyte(busobj, address, bytevalue):
|
||||
if busobj is None:
|
||||
return
|
||||
busobj.write_byte_data(ADDR_ARGONONEREG,address,bytevalue)
|
||||
time.sleep(1)
|
||||
|
||||
def argonregister_getfanspeed(busobj, regsupport=None):
|
||||
return 0
|
||||
|
||||
def argonregister_setfanspeed(busobj, newspeed, regsupport=None):
|
||||
if busobj is None:
|
||||
return
|
||||
|
||||
if newspeed > 100:
|
||||
newspeed = 100
|
||||
elif newspeed < 0:
|
||||
newspeed = 0
|
||||
|
||||
busobj.write_byte(ADDR_ARGONONEFAN,newspeed)
|
||||
time.sleep(1)
|
||||
|
||||
def argonregister_signalpoweroff(busobj):
|
||||
if busobj is None:
|
||||
return
|
||||
|
||||
busobj.write_byte(ADDR_ARGONONEFAN,0xFF)
|
||||
|
||||
def argonregister_setircode(busobj, vallist):
|
||||
if busobj is None:
|
||||
return
|
||||
|
||||
busobj.write_i2c_block_data(ADDR_ARGONONEREG, ADDR_ARGONONEREG_IR, vallist)
|
109
source/scripts/argonregister.py
Normal file
109
source/scripts/argonregister.py
Normal file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
#
|
||||
# Argon Register Helper methods
|
||||
#
|
||||
|
||||
import time
|
||||
import smbus
|
||||
|
||||
# I2C Addresses
|
||||
ADDR_ARGONONEFAN=0x1a
|
||||
ADDR_ARGONONEREG=ADDR_ARGONONEFAN
|
||||
|
||||
# ARGONONEREG Addresses
|
||||
ADDR_ARGONONEREG_DUTYCYCLE=0x80
|
||||
ADDR_ARGONONEREG_FW=0x81
|
||||
ADDR_ARGONONEREG_IR=0x82
|
||||
ADDR_ARGONONEREG_CTRL=0x86
|
||||
|
||||
# Initialize bus
|
||||
def argonregister_initializebusobj():
|
||||
try:
|
||||
return smbus.SMBus(1)
|
||||
except Exception:
|
||||
try:
|
||||
# Older version
|
||||
return smbus.SMBus(0)
|
||||
except Exception:
|
||||
print("Unable to detect i2c")
|
||||
return None
|
||||
|
||||
|
||||
# Checks if the FW supports control registers
|
||||
def argonregister_checksupport(busobj):
|
||||
if busobj is None:
|
||||
return False
|
||||
try:
|
||||
oldval = argonregister_getbyte(busobj, ADDR_ARGONONEREG_DUTYCYCLE)
|
||||
newval = oldval + 1
|
||||
if newval >= 100:
|
||||
newval = 98
|
||||
argonregister_setbyte(busobj, ADDR_ARGONONEREG_DUTYCYCLE, newval)
|
||||
newval = argonregister_getbyte(busobj, ADDR_ARGONONEREG_DUTYCYCLE)
|
||||
if newval != oldval:
|
||||
argonregister_setbyte(busobj, ADDR_ARGONONEREG_DUTYCYCLE, oldval)
|
||||
return True
|
||||
return False
|
||||
except:
|
||||
return False
|
||||
|
||||
def argonregister_getbyte(busobj, address):
|
||||
if busobj is None:
|
||||
return 0
|
||||
return busobj.read_byte_data(ADDR_ARGONONEREG, address)
|
||||
|
||||
def argonregister_setbyte(busobj, address, bytevalue):
|
||||
if busobj is None:
|
||||
return
|
||||
busobj.write_byte_data(ADDR_ARGONONEREG,address,bytevalue)
|
||||
time.sleep(1)
|
||||
|
||||
def argonregister_getfanspeed(busobj, regsupport=None):
|
||||
if busobj is None:
|
||||
return 0
|
||||
|
||||
usereg=False
|
||||
if regsupport is None:
|
||||
usereg=argonregister_checksupport(busobj)
|
||||
else:
|
||||
usereg=regsupport
|
||||
if usereg == True:
|
||||
return argonregister_getbyte(busobj, ADDR_ARGONONEREG_DUTYCYCLE)
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
def argonregister_setfanspeed(busobj, newspeed, regsupport=None):
|
||||
if busobj is None:
|
||||
return
|
||||
|
||||
if newspeed > 100:
|
||||
newspeed = 100
|
||||
elif newspeed < 0:
|
||||
newspeed = 0
|
||||
usereg=False
|
||||
if regsupport is None:
|
||||
usereg=argonregister_checksupport(busobj)
|
||||
else:
|
||||
usereg=regsupport
|
||||
if usereg == True:
|
||||
argonregister_setbyte(busobj, ADDR_ARGONONEREG_DUTYCYCLE, newspeed)
|
||||
else:
|
||||
busobj.write_byte(ADDR_ARGONONEFAN,newspeed)
|
||||
time.sleep(1)
|
||||
|
||||
def argonregister_signalpoweroff(busobj):
|
||||
if busobj is None:
|
||||
return
|
||||
|
||||
if argonregister_checksupport(busobj):
|
||||
argonregister_setbyte(busobj, ADDR_ARGONONEREG_CTRL, 1)
|
||||
else:
|
||||
busobj.write_byte(ADDR_ARGONONEFAN,0xFF)
|
||||
|
||||
def argonregister_setircode(busobj, vallist):
|
||||
if busobj is None:
|
||||
return
|
||||
|
||||
busobj.write_i2c_block_data(ADDR_ARGONONEREG, ADDR_ARGONONEREG_IR, vallist)
|
642
source/scripts/argonrtc.py
Normal file
642
source/scripts/argonrtc.py
Normal file
@ -0,0 +1,642 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import datetime
|
||||
|
||||
#########
|
||||
# Describe Methods
|
||||
#########
|
||||
|
||||
# Helper method to add proper suffix to numbers
|
||||
def getNumberSuffix(numval):
|
||||
onesvalue = numval % 10
|
||||
if onesvalue == 1:
|
||||
return "st"
|
||||
elif onesvalue == 2:
|
||||
return "nd"
|
||||
elif onesvalue == 3:
|
||||
return "rd"
|
||||
return "th"
|
||||
|
||||
def describeHourMinute(hour, minute):
|
||||
if hour < 0:
|
||||
return ""
|
||||
outstr = ""
|
||||
ampmstr = ""
|
||||
if hour <= 0:
|
||||
hour = 0
|
||||
outstr = outstr + "12"
|
||||
ampmstr = "am"
|
||||
elif hour <= 12:
|
||||
outstr = outstr + str(hour)
|
||||
if hour == 12:
|
||||
ampmstr = "pm"
|
||||
else:
|
||||
ampmstr = "am"
|
||||
else:
|
||||
outstr = outstr + str(hour-12)
|
||||
ampmstr = "pm"
|
||||
|
||||
if minute >= 10:
|
||||
outstr = outstr+":"
|
||||
elif minute > 0:
|
||||
outstr = outstr+":0"
|
||||
else:
|
||||
if hour == 0:
|
||||
ampmstr = "mn"
|
||||
elif hour == 12:
|
||||
ampmstr = "nn"
|
||||
return outstr+ampmstr
|
||||
|
||||
if minute <= 0:
|
||||
minute = 0
|
||||
outstr = outstr+str(minute)
|
||||
|
||||
return outstr+ampmstr
|
||||
|
||||
# Describe Schedule Parameter Values
|
||||
def describeSchedule(monthlist, weekdaylist, datelist, hourlist, minutelist):
|
||||
weekdaynamelist = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
|
||||
monthnamelist = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
||||
|
||||
curprefix = ""
|
||||
hasDate = False
|
||||
hasMonth = False
|
||||
foundvalue = False
|
||||
monthdatestr = ""
|
||||
for curmonth in monthlist:
|
||||
for curdate in datelist:
|
||||
if curdate >= 0:
|
||||
hasDate = True
|
||||
if curmonth >= 0:
|
||||
hasMonth = True
|
||||
monthdatestr = monthdatestr + "," + monthnamelist[curmonth-1]+" "+str(curdate) + getNumberSuffix(curdate)
|
||||
else:
|
||||
monthdatestr = monthdatestr + ","+str(curdate) + getNumberSuffix(curdate)
|
||||
else:
|
||||
if curmonth >= 0:
|
||||
monthdatestr = monthdatestr + "," + monthnamelist[curmonth-1]
|
||||
|
||||
if len(monthdatestr) > 0:
|
||||
foundvalue = True
|
||||
# Remove Leading Comma
|
||||
monthdatestr = monthdatestr[1:]
|
||||
if hasMonth == True:
|
||||
curprefix = "Annually:"
|
||||
else:
|
||||
curprefix = "Monthly:"
|
||||
monthdatestr = monthdatestr + " of the Month"
|
||||
monthdatestr = " Every "+monthdatestr
|
||||
|
||||
weekdaystr = ""
|
||||
for curweekday in weekdaylist:
|
||||
if curweekday >= 0:
|
||||
hasDate = True
|
||||
weekdaystr = weekdaystr + "," + weekdaynamelist[curweekday]
|
||||
|
||||
if len(weekdaystr) > 0:
|
||||
foundvalue = True
|
||||
# Remove Leading Comma
|
||||
weekdaystr = weekdaystr[1:]
|
||||
if len(curprefix) == 0:
|
||||
curprefix = "Weekly:"
|
||||
weekdaystr = " on " + weekdaystr
|
||||
else:
|
||||
weekdaystr = ",on " + weekdaystr
|
||||
|
||||
hasHour = False
|
||||
hasMinute = False
|
||||
hourminstr = ""
|
||||
for curhour in hourlist:
|
||||
for curminute in minutelist:
|
||||
if curhour >= 0:
|
||||
hasHour = True
|
||||
if curminute >= 0:
|
||||
hasMinute = True
|
||||
hourminstr = hourminstr + "," + describeHourMinute(curhour, curminute)
|
||||
elif curminute >= 0:
|
||||
hasMinute = True
|
||||
hourminstr = hourminstr + "," + str(curminute) + getNumberSuffix(curminute)
|
||||
|
||||
if len(hourminstr) > 0:
|
||||
foundvalue = True
|
||||
# Remove Leading Comma
|
||||
hourminstr = hourminstr[1:]
|
||||
if hasHour == True:
|
||||
if hasDate == True:
|
||||
hourminstr = "at " + hourminstr
|
||||
else:
|
||||
hourminstr = "Daily: " + hourminstr
|
||||
if hasMinute == False:
|
||||
hourminstr = hourminstr + " every minute"
|
||||
else:
|
||||
if hourminstr == "0":
|
||||
hourminstr = "At the start of every hour"
|
||||
else:
|
||||
hourminstr = "Hourly: At " + hourminstr + " minute"
|
||||
else:
|
||||
hourminstr = "Every minute"
|
||||
|
||||
if len(curprefix) > 0:
|
||||
hourminstr = ","+hourminstr
|
||||
|
||||
return (curprefix + monthdatestr + weekdaystr + hourminstr).strip()
|
||||
|
||||
|
||||
#########
|
||||
# Alarm
|
||||
#########
|
||||
|
||||
# Alarm to UTC/Local time
|
||||
def convertAlarmTimezone(weekday, caldate, hour, minute, toutc):
|
||||
utcdiffsec = getLocaltimeOffset().seconds
|
||||
if toutc == False:
|
||||
utcdiffsec = utcdiffsec*(-1)
|
||||
|
||||
utcdiffsec = utcdiffsec - (utcdiffsec%60)
|
||||
utcdiffmin = utcdiffsec % 3600
|
||||
utcdiffhour = int((utcdiffsec - utcdiffmin)/3600)
|
||||
utcdiffmin = int(utcdiffmin/60)
|
||||
|
||||
addhour = 0
|
||||
if minute >= 0:
|
||||
minute = minute - utcdiffmin
|
||||
if minute < 0:
|
||||
addhour = -1
|
||||
minute = minute + 60
|
||||
elif minute > 59:
|
||||
addhour = 1
|
||||
minute = minute - 60
|
||||
|
||||
addday = 0
|
||||
if hour >= 0:
|
||||
hour = hour - utcdiffhour
|
||||
tmphour = hour + addhour
|
||||
if hour < 0:
|
||||
hour = hour + 24
|
||||
elif hour > 23:
|
||||
hour = hour - 24
|
||||
if tmphour < 0:
|
||||
addday = -1
|
||||
elif tmphour > 23:
|
||||
addday = 1
|
||||
|
||||
if addday != 0:
|
||||
if weekday >= 0:
|
||||
weekday = weekday + addday
|
||||
if weekday < 0:
|
||||
weekday = weekday + 7
|
||||
elif weekday > 6:
|
||||
weekday = weekday - 7
|
||||
if caldate > 0:
|
||||
# Edge cases might not be handled properly though
|
||||
curtime = datetime.datetime.now()
|
||||
maxmonthdate = getLastMonthDate(curtime.year, curtime.month)
|
||||
caldate = caldate + addday
|
||||
if caldate == 0:
|
||||
# move to end of the month
|
||||
caldate = maxmonthdate
|
||||
elif caldate > maxmonthdate:
|
||||
# move to next month
|
||||
caldate = 1
|
||||
|
||||
return [weekday, caldate, hour, minute]
|
||||
|
||||
|
||||
# Get RTC Alarm Setting (Negative values ignored)
|
||||
def getRTCAlarm(weekday, caldate, hour, minute):
|
||||
hasError = False
|
||||
if caldate < 1 and weekday < 0 and hour < 0 and minute < 0:
|
||||
hasError = True
|
||||
elif minute > 59:
|
||||
hasError = True
|
||||
elif hour > 23:
|
||||
hasError = True
|
||||
elif weekday > 6:
|
||||
hasError = True
|
||||
elif caldate > 31:
|
||||
hasError = True
|
||||
|
||||
if hasError == True:
|
||||
return [-1, -1, -1, -1]
|
||||
# Convert to UTC
|
||||
return convertAlarmTimezone(weekday, caldate, hour, minute, True)
|
||||
|
||||
#########
|
||||
# Date/Time tools
|
||||
#########
|
||||
|
||||
# Get local time vs UTC
|
||||
def getLocaltimeOffset():
|
||||
localdatetime = datetime.datetime.now()
|
||||
utcdatetime = datetime.datetime.fromtimestamp(localdatetime.timestamp(), datetime.timezone.utc)
|
||||
# Remove TZ info to allow subtraction
|
||||
utcdatetime = utcdatetime.replace(tzinfo = None)
|
||||
|
||||
return localdatetime - utcdatetime
|
||||
|
||||
|
||||
# Sync Time to RTC Time (for Daemon use)
|
||||
def updateSystemTime(rtctime):
|
||||
os.system("date -s '"+rtctime.isoformat()+"' >/dev/null 2>&1")
|
||||
|
||||
|
||||
#########
|
||||
# Config
|
||||
#########
|
||||
|
||||
# Load config value as array of integers
|
||||
def getConfigValue(valuestr):
|
||||
try:
|
||||
if valuestr == "*":
|
||||
return [-1]
|
||||
tmplist = valuestr.split(",")
|
||||
map_object = map(int, tmplist)
|
||||
return list(map_object)
|
||||
except:
|
||||
return [-1]
|
||||
|
||||
# Load config line data as array of Command schedule
|
||||
def newCommandSchedule(curline):
|
||||
result = []
|
||||
linedata = curline.split(" ")
|
||||
if len(linedata) < 6:
|
||||
return result
|
||||
|
||||
minutelist = getConfigValue(linedata[0])
|
||||
hourlist = getConfigValue(linedata[1])
|
||||
datelist = getConfigValue(linedata[2])
|
||||
#monthlist = getConfigValue(linedata[3])
|
||||
monthlist = [-1] # Certain edge cases will not be handled properly
|
||||
weekdaylist = getConfigValue(linedata[4])
|
||||
|
||||
cmd = ""
|
||||
ctr = 5
|
||||
while ctr < len(linedata):
|
||||
cmd = cmd + " " + linedata[ctr]
|
||||
ctr = ctr + 1
|
||||
cmd = cmd.strip()
|
||||
|
||||
for curmin in minutelist:
|
||||
for curhour in hourlist:
|
||||
for curdate in datelist:
|
||||
for curmonth in monthlist:
|
||||
for curweekday in weekdaylist:
|
||||
result.append({ "minute": curmin, "hour": curhour, "date": curdate, "month":curmonth, "weekday": curweekday, "cmd":cmd })
|
||||
|
||||
return result
|
||||
|
||||
# Save updated config file
|
||||
def saveConfigList(fname, configlist):
|
||||
f = open(fname, "w")
|
||||
f.write("#\n")
|
||||
f.write("# Argon RTC Configuration\n")
|
||||
f.write("# - Follows cron general format, but with only * and csv support\n")
|
||||
f.write("# - Each row follows the following format:\n")
|
||||
f.write("# min hour date month dayOfWeek Command\n")
|
||||
f.write("# e.g. Shutdown daily at 1am\n")
|
||||
f.write("# 0 1 * * * off\n")
|
||||
f.write("# Shutdown daily at 1am and 1pm\n")
|
||||
f.write("# 0 1,13 * * * off\n")
|
||||
f.write("# - Commands are currently on or off only\n")
|
||||
f.write("# - Limititations\n")
|
||||
f.write("# Requires MINUTE value\n")
|
||||
f.write("# Month values are ignored (edge cases not supported)\n")
|
||||
f.write("#\n")
|
||||
|
||||
for config in configlist:
|
||||
f.write(config+"\n")
|
||||
f.close()
|
||||
|
||||
# Remove config line
|
||||
def removeConfigEntry(fname, entryidx):
|
||||
configlist = loadConfigList(fname)
|
||||
if len(configlist) > entryidx:
|
||||
configlist.pop(entryidx)
|
||||
saveConfigList(fname, configlist)
|
||||
|
||||
# Load config list (removes invalid data)
|
||||
def loadConfigList(fname):
|
||||
try:
|
||||
result = []
|
||||
with open(fname, "r") as fp:
|
||||
for curline in fp:
|
||||
if not curline:
|
||||
continue
|
||||
curline = curline.strip().replace('\t', ' ')
|
||||
# Handle special characters that get encoded
|
||||
tmpline = "".join([c if 0x20<=ord(c) and ord(c)<=0x7e else "" for c in curline])
|
||||
|
||||
if not tmpline:
|
||||
continue
|
||||
if tmpline[0] == "#":
|
||||
continue
|
||||
checkdata = tmpline.split(" ")
|
||||
if len(checkdata) > 5:
|
||||
# Don't include every minute type of schedule
|
||||
if checkdata[0] != "*":
|
||||
result.append(tmpline)
|
||||
return result
|
||||
except:
|
||||
return []
|
||||
|
||||
# Form Command Schedule list from config list
|
||||
def formCommandScheduleList(configlist):
|
||||
try:
|
||||
result = []
|
||||
for config in configlist:
|
||||
result = result + newCommandSchedule(config)
|
||||
return result
|
||||
except:
|
||||
return []
|
||||
|
||||
# Describe config list entry
|
||||
def describeConfigListEntry(configlistitem):
|
||||
linedata = configlistitem.split(" ")
|
||||
if len(linedata) < 6:
|
||||
return ""
|
||||
|
||||
minutelist = getConfigValue(linedata[0])
|
||||
hourlist = getConfigValue(linedata[1])
|
||||
datelist = getConfigValue(linedata[2])
|
||||
#monthlist = getConfigValue(linedata[3])
|
||||
monthlist = [-1] # Certain edge cases will not be handled properly
|
||||
weekdaylist = getConfigValue(linedata[4])
|
||||
|
||||
cmd = ""
|
||||
ctr = 5
|
||||
while ctr < len(linedata):
|
||||
cmd = cmd + " " + linedata[ctr]
|
||||
ctr = ctr + 1
|
||||
cmd = cmd.strip().lower()
|
||||
if cmd == "on":
|
||||
cmd = "Startup"
|
||||
else:
|
||||
cmd = "Shutdown"
|
||||
|
||||
return cmd+" | "+describeSchedule(monthlist, weekdaylist, datelist, hourlist, minutelist)
|
||||
|
||||
# Describe config list and show indices
|
||||
def describeConfigList(fname):
|
||||
# 1 is reserved for New schedule
|
||||
ctr = 2
|
||||
configlist = loadConfigList(fname)
|
||||
for config in configlist:
|
||||
tmpline = describeConfigListEntry(config)
|
||||
if len(tmpline) > 0:
|
||||
print(" "+str(ctr)+". ", tmpline)
|
||||
ctr = ctr + 1
|
||||
if ctr == 2:
|
||||
print(" No Existing Schedules")
|
||||
|
||||
# Check Command schedule if it should fire for the give time
|
||||
def checkDateForCommandSchedule(commandschedule, datetimeobj):
|
||||
testminute = commandschedule.get("minute", -1)
|
||||
testhour = commandschedule.get("hour", -1)
|
||||
testdate = commandschedule.get("date", -1)
|
||||
testmonth = commandschedule.get("month", -1)
|
||||
testweekday = commandschedule.get("weekday", -1)
|
||||
|
||||
if testminute < 0 or testminute == datetimeobj.minute:
|
||||
if testhour < 0 or testhour == datetimeobj.hour:
|
||||
if testdate < 0 or testdate == datetimeobj.day:
|
||||
if testmonth < 0 or testmonth == datetimeobj.month:
|
||||
if testweekday < 0:
|
||||
return True
|
||||
else:
|
||||
# python Sunday = 6, RTC Sunday = 0
|
||||
weekDay = datetimeobj.weekday()
|
||||
if weekDay == 6:
|
||||
weekDay = 0
|
||||
else:
|
||||
weekDay = weekDay + 1
|
||||
if testweekday == weekDay:
|
||||
return True
|
||||
return False
|
||||
|
||||
# Get current command
|
||||
def getCommandForTime(commandschedulelist, datetimeobj, checkcmd):
|
||||
ctr = 0
|
||||
while ctr < len(commandschedulelist):
|
||||
testcmd = commandschedulelist[ctr].get("cmd", "")
|
||||
if (testcmd.lower() == checkcmd or len(checkcmd) == 0) and len(testcmd) > 0:
|
||||
if checkDateForCommandSchedule(commandschedulelist[ctr], datetimeobj) == True:
|
||||
return testcmd
|
||||
ctr = ctr + 1
|
||||
return ""
|
||||
|
||||
# Get Last Date of Month
|
||||
def getLastMonthDate(year, month):
|
||||
if month < 12:
|
||||
testtime = datetime.datetime(year, month+1, 1)
|
||||
else:
|
||||
testtime = datetime.datetime(year+1, 1, 1)
|
||||
testtime = testtime - datetime.timedelta(days=1)
|
||||
return testtime.day
|
||||
|
||||
# Increment to the next iteration of command schedule
|
||||
def incrementCommandScheduleTime(commandschedule, testtime, addmode):
|
||||
testminute = commandschedule.get("minute", -1)
|
||||
testhour = commandschedule.get("hour", -1)
|
||||
testdate = commandschedule.get("date", -1)
|
||||
testmonth = commandschedule.get("month", -1)
|
||||
testweekday = commandschedule.get("weekday", -1)
|
||||
|
||||
if addmode == "minute":
|
||||
testfield = commandschedule.get(addmode, -1)
|
||||
if testfield < 0:
|
||||
if testtime.minute < 59:
|
||||
return testtime + datetime.timedelta(minutes=1)
|
||||
else:
|
||||
return incrementCommandScheduleTime(commandschedule, testtime.replace(minute=0), "hour")
|
||||
else:
|
||||
return incrementCommandScheduleTime(commandschedule, testtime, "hour")
|
||||
elif addmode == "hour":
|
||||
testfield = commandschedule.get(addmode, -1)
|
||||
if testfield < 0:
|
||||
if testtime.hour < 23:
|
||||
return testtime + datetime.timedelta(hours=1)
|
||||
else:
|
||||
return incrementCommandScheduleTime(commandschedule, testtime.replace(hour=0), "date")
|
||||
else:
|
||||
return incrementCommandScheduleTime(commandschedule, testtime, "date")
|
||||
elif addmode == "date":
|
||||
testfield = commandschedule.get(addmode, -1)
|
||||
if testfield < 0:
|
||||
maxmonthdate = getLastMonthDate(testtime.year, testtime.month)
|
||||
if testtime.day < maxmonthdate:
|
||||
return testtime + datetime.timedelta(days=1)
|
||||
else:
|
||||
return incrementCommandScheduleTime(commandschedule, testtime.replace(day=1), "month")
|
||||
else:
|
||||
return incrementCommandScheduleTime(commandschedule, testtime, "month")
|
||||
elif addmode == "month":
|
||||
testfield = commandschedule.get(addmode, -1)
|
||||
if testfield < 0:
|
||||
nextmonth = testtime.month
|
||||
nextyear = testtime.year
|
||||
while True:
|
||||
if nextmonth < 12:
|
||||
nextmonth = nextmonth + 1
|
||||
else:
|
||||
nextmonth = 1
|
||||
nextyear = nextyear + 1
|
||||
maxmonthdate = getLastMonthDate(nextyear, nextmonth)
|
||||
if testtime.day <= maxmonthdate:
|
||||
return testtime.replace(month=nextmonth, year=nextyear)
|
||||
else:
|
||||
return incrementCommandScheduleTime(commandschedule, testtime, "year")
|
||||
else:
|
||||
# Year
|
||||
if testtime.month == 2 and testtime.day == 29:
|
||||
# Leap day handling
|
||||
nextyear = testtime.year
|
||||
while True:
|
||||
nextyear = nextyear + 1
|
||||
maxmonthdate = getLastMonthDate(nextyear, testtime.month)
|
||||
if testtime.day <= maxmonthdate:
|
||||
return testtime.replace(year=nextyear)
|
||||
else:
|
||||
return testtime.replace(year=(testtime.year+1))
|
||||
|
||||
# Set Next Alarm on RTC
|
||||
def getNextAlarm(commandschedulelist, prevdatetime):
|
||||
curtime = datetime.datetime.now()
|
||||
if prevdatetime > curtime:
|
||||
return [prevdatetime, -1, -1, -1, -1]
|
||||
|
||||
# Divisible by 4 for leap day
|
||||
checklimityears = 12
|
||||
foundnextcmd = False
|
||||
nextcommandschedule = {}
|
||||
# To be sure it's later than any schedule
|
||||
nextcommandtime = curtime.replace(year=(curtime.year+checklimityears))
|
||||
|
||||
ctr = 0
|
||||
while ctr < len(commandschedulelist):
|
||||
testcmd = commandschedulelist[ctr].get("cmd", "").lower()
|
||||
if testcmd == "on":
|
||||
invaliddata = False
|
||||
testminute = commandschedulelist[ctr].get("minute", -1)
|
||||
testhour = commandschedulelist[ctr].get("hour", -1)
|
||||
testdate = commandschedulelist[ctr].get("date", -1)
|
||||
testmonth = commandschedulelist[ctr].get("month", -1)
|
||||
testweekday = commandschedulelist[ctr].get("weekday", -1)
|
||||
|
||||
tmpminute = testminute
|
||||
tmphour = testhour
|
||||
tmpdate = testdate
|
||||
tmpmonth = testmonth
|
||||
tmpyear = curtime.year
|
||||
|
||||
if tmpminute < 0:
|
||||
tmpminute = curtime.minute
|
||||
|
||||
if tmphour < 0:
|
||||
tmphour = curtime.hour
|
||||
|
||||
if tmpdate < 0:
|
||||
tmpdate = curtime.day
|
||||
|
||||
if tmpmonth < 0:
|
||||
tmpmonth = curtime.month
|
||||
|
||||
maxmonthdate = getLastMonthDate(tmpyear, tmpmonth)
|
||||
if tmpdate > maxmonthdate:
|
||||
# Invalid month date
|
||||
if testdate < 0:
|
||||
tmpdate = maxmonthdate
|
||||
else:
|
||||
# Date is fixed
|
||||
if testminute < 0:
|
||||
tmpminute = 0
|
||||
if testhour < 0:
|
||||
tmphour = 0
|
||||
if testmonth < 0 and testdate <= 31:
|
||||
# Look for next valid month
|
||||
while tmpdate > maxmonthdate:
|
||||
if tmpmonth < 12:
|
||||
tmpmonth = tmpmonth + 1
|
||||
else:
|
||||
tmpmonth = 1
|
||||
tmpyear = tmpyear + 1
|
||||
maxmonthdate = getLastMonthDate(tmpyear, tmpmonth)
|
||||
elif tmpdate == 29 and tmpmonth == 2:
|
||||
# Fixed to leap day
|
||||
while tmpdate > maxmonthdate:
|
||||
tmpyear = tmpyear + 1
|
||||
maxmonthdate = getLastMonthDate(tmpyear, tmpmonth)
|
||||
else:
|
||||
invaliddata = True
|
||||
if invaliddata == False:
|
||||
try:
|
||||
testtime = datetime.datetime(tmpyear, tmpmonth, tmpdate, tmphour, tmpminute)
|
||||
except:
|
||||
# Force time diff
|
||||
testtime = curtime - datetime.timedelta(hours=1)
|
||||
tmptimediff = (curtime - testtime).total_seconds()
|
||||
else:
|
||||
tmptimediff = 0
|
||||
|
||||
if testweekday >= 0:
|
||||
# Day of Week check
|
||||
# python Sunday = 6, RTC Sunday = 0
|
||||
weekDay = testtime.weekday()
|
||||
if weekDay == 6:
|
||||
weekDay = 0
|
||||
else:
|
||||
weekDay = weekDay + 1
|
||||
|
||||
|
||||
if weekDay != testweekday or tmptimediff > 0:
|
||||
# Resulting 0-ed time will be <= the testtime
|
||||
if testminute < 0:
|
||||
testtime = testtime.replace(minute=0)
|
||||
if testhour < 0:
|
||||
testtime = testtime.replace(hour=0)
|
||||
|
||||
dayoffset = testweekday-weekDay
|
||||
if dayoffset < 0:
|
||||
dayoffset = dayoffset + 7
|
||||
elif dayoffset == 0:
|
||||
dayoffset = 7
|
||||
|
||||
testtime = testtime + datetime.timedelta(days=dayoffset)
|
||||
|
||||
# Just look for the next valid weekday; Can be optimized
|
||||
while checkDateForCommandSchedule(commandschedulelist[ctr], testtime) == False and (testtime.year - curtime.year) < checklimityears:
|
||||
testtime = testtime + datetime.timedelta(days=7)
|
||||
|
||||
if (testtime.year - curtime.year) >= checklimityears:
|
||||
# Too many iterations, abort/ignore
|
||||
tmptimediff = 0
|
||||
else:
|
||||
tmptimediff = (curtime - testtime).total_seconds()
|
||||
if tmptimediff > 0:
|
||||
# Find next iteration that's greater than the current time (Day of Week check already handled)
|
||||
while tmptimediff >= 0:
|
||||
testtime = incrementCommandScheduleTime(commandschedulelist[ctr], testtime, "minute")
|
||||
tmptimediff = (curtime - testtime).total_seconds()
|
||||
|
||||
if nextcommandtime > testtime and tmptimediff < 0:
|
||||
nextcommandschedule = commandschedulelist[ctr]
|
||||
nextcommandtime = testtime
|
||||
foundnextcmd = True
|
||||
|
||||
|
||||
ctr = ctr + 1
|
||||
if foundnextcmd == True:
|
||||
# Schedule Alarm
|
||||
# Assume no date,weekday involved just shift the hour and minute accordingly
|
||||
paramminute = nextcommandschedule.get("minute", -1)
|
||||
paramhour = nextcommandschedule.get("hour", -1)
|
||||
if nextcommandschedule.get("weekday", -1) >=0 or nextcommandschedule.get("date", -1) > 0:
|
||||
# Set alarm based on hour/minute of next occurrence to factor in timezone changes if any
|
||||
paramminute = nextcommandtime.minute
|
||||
paramhour = nextcommandtime.hour
|
||||
weekday, caldate, hour, minute = getRTCAlarm(nextcommandschedule.get("weekday", -1), nextcommandschedule.get("date", -1), paramhour, paramminute)
|
||||
return [nextcommandtime, weekday, caldate, hour, minute]
|
||||
|
||||
# This will ensure that this will be replaced next iteration
|
||||
return [curtime, -1, -1, -1, -1]
|
||||
|
172
source/scripts/argonstatus.py
Normal file
172
source/scripts/argonstatus.py
Normal file
@ -0,0 +1,172 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append("/etc/argon/")
|
||||
from argonsysinfo import *
|
||||
from argonregister import *
|
||||
from argononed import *
|
||||
|
||||
def getFahrenheit(celsiustemp):
|
||||
try:
|
||||
return (32+9*(celsiustemp)/5)
|
||||
except:
|
||||
return 0
|
||||
|
||||
|
||||
temperature="C"
|
||||
tmpconfig=load_unitconfig(UNIT_CONFIGFILE)
|
||||
if "temperature" in tmpconfig:
|
||||
temperature = tmpconfig["temperature"]
|
||||
|
||||
baseleftoffset = ""
|
||||
|
||||
stdleftoffset = " "
|
||||
|
||||
#if len(sys.argv) > 2:
|
||||
# baseleftoffset = stdleftoffset
|
||||
baseleftoffset = stdleftoffset
|
||||
|
||||
argctr = 1
|
||||
while argctr < len(sys.argv):
|
||||
cmd = sys.argv[argctr].lower()
|
||||
argctr = argctr + 1
|
||||
if baseleftoffset != "":
|
||||
print(cmd.upper(),"INFORMATION:")
|
||||
if cmd == "cpu usage":
|
||||
# CPU Usage
|
||||
curlist = argonsysinfo_listcpuusage()
|
||||
|
||||
while len(curlist) > 0:
|
||||
curline = ""
|
||||
tmpitem = curlist.pop(0)
|
||||
curline = tmpitem["title"]+": "+str(tmpitem["value"])+"%"
|
||||
print(baseleftoffset+curline)
|
||||
elif cmd == "storage":
|
||||
# Storage Info
|
||||
curlist = []
|
||||
try:
|
||||
tmpobj = argonsysinfo_listhddusage()
|
||||
for curdev in tmpobj:
|
||||
curlist.append({"title": curdev, "value": argonsysinfo_kbstr(tmpobj[curdev]['total']), "usage": int(100*tmpobj[curdev]['used']/tmpobj[curdev]['total']) })
|
||||
#curlist = argonsysinfo_liststoragetotal()
|
||||
except Exception:
|
||||
curlist = []
|
||||
|
||||
while len(curlist) > 0:
|
||||
tmpitem = curlist.pop(0)
|
||||
# Right column first, safer to overwrite white space
|
||||
print(baseleftoffset+tmpitem["title"], str(tmpitem["usage"])+"%","used of", tmpitem["value"])
|
||||
|
||||
elif cmd == "raid":
|
||||
# Raid Info
|
||||
curlist = []
|
||||
try:
|
||||
tmpobj = argonsysinfo_listraid()
|
||||
curlist = tmpobj['raidlist']
|
||||
except Exception:
|
||||
curlist = []
|
||||
|
||||
if len(curlist) > 0:
|
||||
tmpitem = curlist.pop(0)
|
||||
print(baseleftoffset+tmpitem["title"], tmpitem["value"], argonsysinfo_kbstr(tmpitem["info"]["size"]))
|
||||
|
||||
if len(tmpitem['info']['state']) > 0:
|
||||
print(baseleftoffset+stdleftoffset,tmpitem['info']['state'])
|
||||
|
||||
if len(tmpitem['info']['rebuildstat']) > 0:
|
||||
print(baseleftoffset+stdleftoffset,"Rebuild:" + tmpitem['info']['rebuildstat'])
|
||||
|
||||
|
||||
print(baseleftoffset+stdleftoffset,"Active:"+str(int(tmpitem["info"]["active"]))+"/"+str(int(tmpitem["info"]["devices"])))
|
||||
print(baseleftoffset+stdleftoffset,"Working:"+str(int(tmpitem["info"]["working"]))+"/"+str(int(tmpitem["info"]["devices"])))
|
||||
print(baseleftoffset+stdleftoffset,"Failed:"+str(int(tmpitem["info"]["failed"]))+"/"+str(int(tmpitem["info"]["devices"])))
|
||||
else:
|
||||
print(baseleftoffset+stdleftoffset,"N/A")
|
||||
|
||||
elif cmd == "ram":
|
||||
# RAM
|
||||
try:
|
||||
tmpraminfo = argonsysinfo_getram()
|
||||
print(baseleftoffset+tmpraminfo[0],"of", tmpraminfo[1])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
elif cmd == "temperature":
|
||||
# Temp
|
||||
try:
|
||||
hddtempctr = 0
|
||||
maxcval = 0
|
||||
mincval = 200
|
||||
|
||||
alltempobj = {"cpu": argonsysinfo_getcputemp()}
|
||||
# Get min/max of hdd temp
|
||||
hddtempobj = argonsysinfo_gethddtemp()
|
||||
for curdev in hddtempobj:
|
||||
alltempobj[curdev] = hddtempobj[curdev]
|
||||
if hddtempobj[curdev] < mincval:
|
||||
mincval = hddtempobj[curdev]
|
||||
if hddtempobj[curdev] > maxcval:
|
||||
maxcval = hddtempobj[curdev]
|
||||
hddtempctr = hddtempctr + 1
|
||||
|
||||
if hddtempctr > 0:
|
||||
alltempobj["hdd min"]=mincval
|
||||
alltempobj["hdd max"]=maxcval
|
||||
|
||||
for curdev in alltempobj:
|
||||
if temperature == "C":
|
||||
# Celsius
|
||||
tmpstr = str(alltempobj[curdev])
|
||||
if len(tmpstr) > 4:
|
||||
tmpstr = tmpstr[0:4]
|
||||
else:
|
||||
# Fahrenheit
|
||||
tmpstr = str(getFahrenheit(alltempobj[curdev]))
|
||||
if len(tmpstr) > 5:
|
||||
tmpstr = tmpstr[0:5]
|
||||
print(baseleftoffset+curdev.upper()+": "+ tmpstr+ chr(176) +temperature)
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
elif cmd == "ip":
|
||||
# IP Address
|
||||
try:
|
||||
print(baseleftoffset+argonsysinfo_getip())
|
||||
except Exception:
|
||||
pass
|
||||
elif cmd == "fan speed":
|
||||
# Fan Speed
|
||||
try:
|
||||
newspeed = argonregister_getfanspeed(argonregister_initializebusobj())
|
||||
if newspeed <= 0:
|
||||
fanconfig = load_fancpuconfig()
|
||||
fanhddconfig = load_fanhddconfig()
|
||||
|
||||
# Speed based on CPU Temp
|
||||
val = argonsysinfo_getcputemp()
|
||||
newspeed = get_fanspeed(val, fanconfig)
|
||||
|
||||
val = argonsysinfo_getmaxhddtemp()
|
||||
tmpspeed = get_fanspeed(val, fanhddconfig)
|
||||
if tmpspeed > newspeed:
|
||||
newspeed = tmpspeed
|
||||
print(baseleftoffset+"Fan Speed",str(newspeed))
|
||||
except Exception:
|
||||
pass
|
||||
elif cmd == "fan configuration":
|
||||
fanconfig = load_fancpuconfig()
|
||||
fanhddconfig = load_fanhddconfig()
|
||||
|
||||
if len(fanhddconfig) > 0:
|
||||
print(baseleftoffset+"Fan Temp-Speed cut-offs")
|
||||
for curconfig in fanconfig:
|
||||
print(baseleftoffset+stdleftoffset,curconfig)
|
||||
|
||||
if len(fanhddconfig) > 0:
|
||||
print(baseleftoffset+"HDD Temp-Speed cut-offs")
|
||||
for curconfig in fanhddconfig:
|
||||
print(baseleftoffset+stdleftoffset,curconfig)
|
||||
|
||||
|
394
source/scripts/argonsysinfo.py
Normal file
394
source/scripts/argonsysinfo.py
Normal file
@ -0,0 +1,394 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
#
|
||||
# Misc methods to retrieve system information.
|
||||
#
|
||||
|
||||
import os
|
||||
import time
|
||||
import socket
|
||||
|
||||
def argonsysinfo_listcpuusage(sleepsec = 1):
|
||||
outputlist = []
|
||||
curusage_a = argonsysinfo_getcpuusagesnapshot()
|
||||
time.sleep(sleepsec)
|
||||
curusage_b = argonsysinfo_getcpuusagesnapshot()
|
||||
|
||||
for cpuname in curusage_a:
|
||||
if cpuname == "cpu":
|
||||
continue
|
||||
if curusage_a[cpuname]["total"] == curusage_b[cpuname]["total"]:
|
||||
outputlist.append({"title": cpuname, "value": "0%"})
|
||||
else:
|
||||
total = curusage_b[cpuname]["total"]-curusage_a[cpuname]["total"]
|
||||
idle = curusage_b[cpuname]["idle"]-curusage_a[cpuname]["idle"]
|
||||
outputlist.append({"title": cpuname, "value": int(100*(total-idle)/(total))})
|
||||
return outputlist
|
||||
|
||||
def argonsysinfo_getcpuusagesnapshot():
|
||||
cpupercent = {}
|
||||
errorflag = False
|
||||
try:
|
||||
cpuctr = 0
|
||||
# user, nice, system, idle, iowait, irc, softirq, steal, guest, guest nice
|
||||
tempfp = open("/proc/stat", "r")
|
||||
alllines = tempfp.readlines()
|
||||
for temp in alllines:
|
||||
temp = temp.replace('\t', ' ')
|
||||
temp = temp.strip()
|
||||
while temp.find(" ") >= 0:
|
||||
temp = temp.replace(" ", " ")
|
||||
if len(temp) < 3:
|
||||
cpuctr = cpuctr +1
|
||||
continue
|
||||
|
||||
checkname = temp[0:3]
|
||||
if checkname == "cpu":
|
||||
infolist = temp.split(" ")
|
||||
idle = 0
|
||||
total = 0
|
||||
colctr = 1
|
||||
while colctr < len(infolist):
|
||||
curval = int(infolist[colctr])
|
||||
if colctr == 4 or colctr == 5:
|
||||
idle = idle + curval
|
||||
total = total + curval
|
||||
colctr = colctr + 1
|
||||
if total > 0:
|
||||
cpupercent[infolist[0]] = {"total": total, "idle": idle}
|
||||
cpuctr = cpuctr +1
|
||||
|
||||
tempfp.close()
|
||||
except IOError:
|
||||
errorflag = True
|
||||
return cpupercent
|
||||
|
||||
|
||||
def argonsysinfo_liststoragetotal():
|
||||
outputlist = []
|
||||
ramtotal = 0
|
||||
errorflag = False
|
||||
|
||||
try:
|
||||
hddctr = 0
|
||||
tempfp = open("/proc/partitions", "r")
|
||||
alllines = tempfp.readlines()
|
||||
|
||||
for temp in alllines:
|
||||
temp = temp.replace('\t', ' ')
|
||||
temp = temp.strip()
|
||||
while temp.find(" ") >= 0:
|
||||
temp = temp.replace(" ", " ")
|
||||
infolist = temp.split(" ")
|
||||
if len(infolist) >= 4:
|
||||
# Check if header
|
||||
if infolist[3] != "name":
|
||||
parttype = infolist[3][0:3]
|
||||
if parttype == "ram":
|
||||
ramtotal = ramtotal + int(infolist[2])
|
||||
elif parttype[0:2] == "sd" or parttype[0:2] == "hd":
|
||||
lastchar = infolist[3][-1]
|
||||
if lastchar.isdigit() == False:
|
||||
outputlist.append({"title": infolist[3], "value": argonsysinfo_kbstr(int(infolist[2]))})
|
||||
else:
|
||||
# SD Cards
|
||||
lastchar = infolist[3][-2]
|
||||
if lastchar[0] != "p":
|
||||
outputlist.append({"title": infolist[3], "value": argonsysinfo_kbstr(int(infolist[2]))})
|
||||
|
||||
tempfp.close()
|
||||
#outputlist.append({"title": "ram", "value": argonsysinfo_kbstr(ramtotal)})
|
||||
except IOError:
|
||||
errorflag = True
|
||||
return outputlist
|
||||
|
||||
def argonsysinfo_getram():
|
||||
totalram = 0
|
||||
totalfree = 0
|
||||
tempfp = open("/proc/meminfo", "r")
|
||||
alllines = tempfp.readlines()
|
||||
|
||||
for temp in alllines:
|
||||
temp = temp.replace('\t', ' ')
|
||||
temp = temp.strip()
|
||||
while temp.find(" ") >= 0:
|
||||
temp = temp.replace(" ", " ")
|
||||
infolist = temp.split(" ")
|
||||
if len(infolist) >= 2:
|
||||
if infolist[0] == "MemTotal:":
|
||||
totalram = int(infolist[1])
|
||||
elif infolist[0] == "MemFree:":
|
||||
totalfree = totalfree + int(infolist[1])
|
||||
elif infolist[0] == "Buffers:":
|
||||
totalfree = totalfree + int(infolist[1])
|
||||
elif infolist[0] == "Cached:":
|
||||
totalfree = totalfree + int(infolist[1])
|
||||
if totalram == 0:
|
||||
return "0%"
|
||||
return [str(int(100*totalfree/totalram))+"%", str((totalram+512*1024)>>20)+"GB"]
|
||||
|
||||
def argonsysinfo_getcputemp():
|
||||
try:
|
||||
tempfp = open("/sys/class/thermal/thermal_zone0/temp", "r")
|
||||
temp = tempfp.readline()
|
||||
tempfp.close()
|
||||
#cval = temp/1000
|
||||
#fval = 32+9*temp/5000
|
||||
return float(int(temp)/1000)
|
||||
except IOError:
|
||||
return 0
|
||||
|
||||
|
||||
def argonsysinfo_getmaxhddtemp():
|
||||
maxtempval = 0
|
||||
try:
|
||||
hddtempobj = argonsysinfo_gethddtemp()
|
||||
for curdev in hddtempobj:
|
||||
if hddtempobj[curdev] > maxtempval:
|
||||
maxtempval = hddtempobj[curdev]
|
||||
return maxtempval
|
||||
except:
|
||||
return maxtempval
|
||||
|
||||
def argonsysinfo_gethddtemp():
|
||||
# May 2022: Used smartctl, hddtemp is not available on some platforms
|
||||
hddtempcmd = "/usr/sbin/smartctl"
|
||||
if os.path.exists(hddtempcmd) == False:
|
||||
# Fallback for now
|
||||
hddtempcmd = "/usr/sbin/hddtemp"
|
||||
|
||||
outputobj = {}
|
||||
if os.path.exists(hddtempcmd):
|
||||
try:
|
||||
tmp = os.popen("lsblk | grep -e '0 disk' | awk '{print $1}'").read()
|
||||
alllines = tmp.split("\n")
|
||||
for curdev in alllines:
|
||||
if curdev[0:2] == "sd" or curdev[0:2] == "hd":
|
||||
tempval = argonsysinfo_getdevhddtemp(hddtempcmd,curdev)
|
||||
if tempval > 0:
|
||||
outputobj[curdev] = tempval
|
||||
return outputobj
|
||||
except:
|
||||
return outputobj
|
||||
return outputobj
|
||||
|
||||
def argonsysinfo_getdevhddtemp(hddtempcmd, curdev):
|
||||
cmdstr = ""
|
||||
if hddtempcmd == "/usr/sbin/hddtemp":
|
||||
cmdstr = "/usr/sbin/hddtemp -n sata:/dev/"+curdev
|
||||
elif hddtempcmd == "/usr/sbin/smartctl":
|
||||
cmdstr = "/usr/sbin/smartctl -d sat -A /dev/"+curdev+" | grep Temperature_Celsius | awk '{print $10}'"
|
||||
|
||||
tempval = 0
|
||||
if len(cmdstr) > 0:
|
||||
try:
|
||||
temperaturestr = os.popen(cmdstr+" 2>&1").read()
|
||||
tempval = float(temperaturestr)
|
||||
except:
|
||||
tempval = -1
|
||||
|
||||
return tempval
|
||||
|
||||
def argonsysinfo_getip():
|
||||
ipaddr = ""
|
||||
st = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
# Connect to nonexistent device
|
||||
st.connect(('254.255.255.255', 1))
|
||||
ipaddr = st.getsockname()[0]
|
||||
except Exception:
|
||||
ipaddr = 'N/A'
|
||||
finally:
|
||||
st.close()
|
||||
return ipaddr
|
||||
|
||||
|
||||
def argonsysinfo_getrootdev():
|
||||
tmp = os.popen('mount').read()
|
||||
alllines = tmp.split("\n")
|
||||
|
||||
for temp in alllines:
|
||||
temp = temp.replace('\t', ' ')
|
||||
temp = temp.strip()
|
||||
while temp.find(" ") >= 0:
|
||||
temp = temp.replace(" ", " ")
|
||||
infolist = temp.split(" ")
|
||||
if len(infolist) >= 3:
|
||||
|
||||
if infolist[2] == "/":
|
||||
return infolist[0]
|
||||
return ""
|
||||
|
||||
def argonsysinfo_listhddusage():
|
||||
outputobj = {}
|
||||
raidlist = argonsysinfo_listraid()
|
||||
raiddevlist = []
|
||||
raidctr = 0
|
||||
while raidctr < len(raidlist['raidlist']):
|
||||
raiddevlist.append(raidlist['raidlist'][raidctr]['title'])
|
||||
# TODO: May need to use different method for each raid type (i.e. check raidlist['raidlist'][raidctr]['value'])
|
||||
#outputobj[raidlist['raidlist'][raidctr]['title']] = {"used":int(raidlist['raidlist'][raidctr]['info']['used']), "total":int(raidlist['raidlist'][raidctr]['info']['size'])}
|
||||
raidctr = raidctr + 1
|
||||
|
||||
rootdev = argonsysinfo_getrootdev()
|
||||
|
||||
tmp = os.popen('df').read()
|
||||
alllines = tmp.split("\n")
|
||||
|
||||
for temp in alllines:
|
||||
temp = temp.replace('\t', ' ')
|
||||
temp = temp.strip()
|
||||
while temp.find(" ") >= 0:
|
||||
temp = temp.replace(" ", " ")
|
||||
infolist = temp.split(" ")
|
||||
if len(infolist) >= 6:
|
||||
if infolist[1] == "Size":
|
||||
continue
|
||||
if len(infolist[0]) < 5:
|
||||
continue
|
||||
elif infolist[0][0:5] != "/dev/":
|
||||
continue
|
||||
curdev = infolist[0]
|
||||
if curdev == "/dev/root" and rootdev != "":
|
||||
curdev = rootdev
|
||||
tmpidx = curdev.rfind("/")
|
||||
if tmpidx >= 0:
|
||||
curdev = curdev[tmpidx+1:]
|
||||
|
||||
if curdev in raidlist['hddlist']:
|
||||
# Skip devices that are part of a RAID setup
|
||||
continue
|
||||
elif curdev in raiddevlist:
|
||||
# Skip RAID ID that already have size data
|
||||
# (use df information otherwise)
|
||||
if curdev in outputobj:
|
||||
continue
|
||||
elif curdev[0:2] == "sd" or curdev[0:2] == "hd":
|
||||
curdev = curdev[0:-1]
|
||||
else:
|
||||
curdev = curdev[0:-2]
|
||||
|
||||
# Aggregate values (i.e. sda1, sda2 to sda)
|
||||
if curdev in outputobj:
|
||||
outputobj[curdev] = {"used":outputobj[curdev]['used']+int(infolist[2]), "total":outputobj[curdev]['total']+int(infolist[1])}
|
||||
else:
|
||||
outputobj[curdev] = {"used":int(infolist[2]), "total":int(infolist[1])}
|
||||
|
||||
return outputobj
|
||||
|
||||
def argonsysinfo_kbstr(kbval, wholenumbers = True):
|
||||
remainder = 0
|
||||
suffixidx = 0
|
||||
suffixlist = ["KB", "MB", "GB", "TB"]
|
||||
while kbval > 1023 and suffixidx < len(suffixlist):
|
||||
remainder = kbval & 1023
|
||||
kbval = kbval >> 10
|
||||
suffixidx = suffixidx + 1
|
||||
|
||||
#return str(kbval)+"."+str(remainder) + suffixlist[suffixidx]
|
||||
remainderstr = ""
|
||||
if kbval < 100 and wholenumbers == False:
|
||||
remainder = int((remainder+50)/100)
|
||||
if remainder > 0:
|
||||
remainderstr = "."+str(remainder)
|
||||
elif remainder >= 500:
|
||||
kbval = kbval + 1
|
||||
return str(kbval)+remainderstr + suffixlist[suffixidx]
|
||||
|
||||
def argonsysinfo_listraid():
|
||||
hddlist = []
|
||||
outputlist = []
|
||||
# cat /proc/mdstat
|
||||
# multiple mdxx from mdstat
|
||||
# mdadm -D /dev/md1
|
||||
|
||||
ramtotal = 0
|
||||
errorflag = False
|
||||
try:
|
||||
hddctr = 0
|
||||
tempfp = open("/proc/mdstat", "r")
|
||||
alllines = tempfp.readlines()
|
||||
for temp in alllines:
|
||||
temp = temp.replace('\t', ' ')
|
||||
temp = temp.strip()
|
||||
while temp.find(" ") >= 0:
|
||||
temp = temp.replace(" ", " ")
|
||||
infolist = temp.split(" ")
|
||||
if len(infolist) >= 4:
|
||||
|
||||
# Check if raid info
|
||||
if infolist[0] != "Personalities" and infolist[1] == ":":
|
||||
devname = infolist[0]
|
||||
raidtype = infolist[3]
|
||||
#raidstatus = infolist[2]
|
||||
hddctr = 4
|
||||
while hddctr < len(infolist):
|
||||
tmpdevname = infolist[hddctr]
|
||||
tmpidx = tmpdevname.find("[")
|
||||
if tmpidx >= 0:
|
||||
tmpdevname = tmpdevname[0:tmpidx]
|
||||
hddlist.append(tmpdevname)
|
||||
hddctr = hddctr + 1
|
||||
devdetail = argonsysinfo_getraiddetail(devname)
|
||||
outputlist.append({"title": devname, "value": raidtype, "info": devdetail})
|
||||
|
||||
tempfp.close()
|
||||
except IOError:
|
||||
# No raid
|
||||
errorflag = True
|
||||
|
||||
return {"raidlist": outputlist, "hddlist": hddlist}
|
||||
|
||||
|
||||
def argonsysinfo_getraiddetail(devname):
|
||||
state = ""
|
||||
raidtype = ""
|
||||
size = 0
|
||||
used = 0
|
||||
total = 0
|
||||
working = 0
|
||||
active = 0
|
||||
failed = 0
|
||||
spare = 0
|
||||
rebuildstat = ""
|
||||
tmp = os.popen('mdadm -D /dev/'+devname).read()
|
||||
alllines = tmp.split("\n")
|
||||
|
||||
for temp in alllines:
|
||||
temp = temp.replace('\t', ' ')
|
||||
temp = temp.strip()
|
||||
while temp.find(" ") >= 0:
|
||||
temp = temp.replace(" ", " ")
|
||||
infolist = temp.split(" : ")
|
||||
if len(infolist) == 2:
|
||||
if infolist[0].lower() == "raid level":
|
||||
raidtype = infolist[1]
|
||||
elif infolist[0].lower() == "array size":
|
||||
tmpidx = infolist[1].find(" ")
|
||||
if tmpidx > 0:
|
||||
size = (infolist[1][0:tmpidx])
|
||||
elif infolist[0].lower() == "used dev size":
|
||||
tmpidx = infolist[1].find(" ")
|
||||
if tmpidx > 0:
|
||||
used = (infolist[1][0:tmpidx])
|
||||
elif infolist[0].lower() == "state":
|
||||
tmpidx = infolist[1].rfind(" ")
|
||||
if tmpidx > 0:
|
||||
state = (infolist[1][tmpidx+1:])
|
||||
else:
|
||||
state = infolist[1]
|
||||
elif infolist[0].lower() == "total devices":
|
||||
total = infolist[1]
|
||||
elif infolist[0].lower() == "active devices":
|
||||
active = infolist[1]
|
||||
elif infolist[0].lower() == "working devices":
|
||||
working = infolist[1]
|
||||
elif infolist[0].lower() == "failed devices":
|
||||
failed = infolist[1]
|
||||
elif infolist[0].lower() == "spare devices":
|
||||
spare = infolist[1]
|
||||
elif infolist[0].lower() == "rebuild status":
|
||||
tmpidx = infolist[1].find("%")
|
||||
if tmpidx > 0:
|
||||
rebuildstat = (infolist[1][0:tmpidx])+"%"
|
||||
return {"state": state, "raidtype": raidtype, "size": int(size), "used": int(used), "devices": int(total), "active": int(active), "working": int(working), "failed": int(failed), "spare": int(spare), "rebuildstat": rebuildstat}
|
42
source/tools/setntpserver.sh
Normal file
42
source/tools/setntpserver.sh
Normal file
@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
NTPSERVER="time.google.com"
|
||||
TMPCONFIG=/dev/shm/tmpconfig.conf
|
||||
|
||||
|
||||
# timesyncd
|
||||
CONFIG=/etc/systemd/timesyncd.conf
|
||||
if [ -f "$CONFIG" ]
|
||||
then
|
||||
cat "$CONFIG" | grep -v -e 'NTP=' > "$TMPCONFIG"
|
||||
echo "NTP=$NTPSERVER" >> "$TMPCONFIG"
|
||||
|
||||
sudo chown root:root "$TMPCONFIG"
|
||||
sudo chmod 644 "$TMPCONFIG"
|
||||
sudo mv "$TMPCONFIG" "$CONFIG"
|
||||
|
||||
# /usr/sbin/ntpd
|
||||
|
||||
sudo service systemd-timesyncd restart > /dev/null 2>&1
|
||||
fi
|
||||
|
||||
|
||||
for CURSERVICECONFIG in ntp chrony
|
||||
do
|
||||
CONFIG=/etc/${CURSERVICECONFIG}.conf
|
||||
if [ -f "$CONFIG" ]
|
||||
then
|
||||
cat "$CONFIG" | grep -v -e 'pool ' > "$TMPCONFIG"
|
||||
#echo "server $NTPSERVER" >> "$TMPCONFIG"
|
||||
echo "pool time1.google.com iburst" >> "$TMPCONFIG"
|
||||
echo "pool time2.google.com iburst" >> "$TMPCONFIG"
|
||||
echo "pool time3.google.com iburst" >> "$TMPCONFIG"
|
||||
echo "pool time4.google.com iburst" >> "$TMPCONFIG"
|
||||
|
||||
sudo chown root:root "$TMPCONFIG"
|
||||
sudo chmod 644 "$TMPCONFIG"
|
||||
sudo mv "$TMPCONFIG" "$CONFIG"
|
||||
|
||||
sudo service ${CURSERVICECONFIG} restart > /dev/null 2>&1
|
||||
fi
|
||||
done
|
Reference in New Issue
Block a user