Automated Change by GitHub Action

This commit is contained in:
okunze
2025-06-11 12:21:48 +00:00
committed by github-actions[bot]
parent 1a7ab2e005
commit 755a2ca262
46 changed files with 6182 additions and 9 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

BIN
source/argoneon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
source/oled/bgcpu.bin Normal file

Binary file not shown.

BIN
source/oled/bgdefault.bin Normal file

Binary file not shown.

BIN
source/oled/bgip.bin Normal file

Binary file not shown.

BIN
source/oled/bgraid.bin Normal file

Binary file not shown.

BIN
source/oled/bgram.bin Normal file

Binary file not shown.

BIN
source/oled/bgstorage.bin Normal file

Binary file not shown.

BIN
source/oled/bgtemp.bin Normal file

Binary file not shown.

BIN
source/oled/bgtime.bin Normal file

Binary file not shown.

BIN
source/oled/font16x12.bin Normal file

Binary file not shown.

BIN
source/oled/font16x8.bin Normal file

Binary file not shown.

BIN
source/oled/font24x16.bin Normal file

Binary file not shown.

BIN
source/oled/font32x24.bin Normal file

Binary file not shown.

BIN
source/oled/font48x32.bin Normal file

Binary file not shown.

BIN
source/oled/font64x48.bin Normal file

Binary file not shown.

BIN
source/oled/font8x6.bin Normal file

Binary file not shown.

BIN
source/oled/logo1v5.bin Normal file

Binary file not shown.

View 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

View 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()

View 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

View 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

View 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."

View 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

View 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

View 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)

View 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

View 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
View 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()

View 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

View 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

View 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

View File

@ -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

View 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
View 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)

View 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

View 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

View 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

View 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")

View 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()

View 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)

View 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
View 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]

View 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)

View 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}

View 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