Compare commits
20 Commits
b8e540b991
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| a7203e0777 | |||
| 57498e55cd | |||
| d018932082 | |||
| 4726434b51 | |||
| 9fcd379747 | |||
| 093deb83cd | |||
| ba8a9c4664 | |||
| c05a4ebbfb | |||
| 73215692ce | |||
| f0aeadea8b | |||
| c26498ae91 | |||
| f3386d5f01 | |||
| b58a168f89 | |||
| bd6f98d5ef | |||
| 377d676348 | |||
| 9b506fd5f0 | |||
| 755a2ca262 | |||
| 1a7ab2e005 | |||
| d3055fdb9c | |||
| 59472bd224 |
@@ -15,32 +15,326 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
# https://github.com/marketplace/actions/checkout
|
# https://github.com/marketplace/actions/checkout
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3.5.3
|
uses: actions/checkout@v4.2.2
|
||||||
- name: Create download folder
|
- name: Create ./download folder
|
||||||
run: mkdir -p ./download
|
run: mkdir -p ./download
|
||||||
|
- name: Create ./download/firmware folder
|
||||||
|
run: mkdir -p ./download/firmware
|
||||||
|
- name: Create ./download/oled folder
|
||||||
|
run: mkdir -p ./download/oled
|
||||||
|
- name: Create ./download/scripts folder
|
||||||
|
run: mkdir -p ./download/scripts
|
||||||
|
- name: Create ./download/tools folder
|
||||||
|
run: mkdir -p ./download/tools
|
||||||
|
- name: Create ./download/ups folder
|
||||||
|
run: mkdir -p ./download/ups
|
||||||
# https://github.com/marketplace/actions/github-action-for-wget
|
# https://github.com/marketplace/actions/github-action-for-wget
|
||||||
|
- name: Github Action for wget (ar1config.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ar1config.png -P ./download
|
||||||
- name: Github Action for wget (argon1.sh)
|
- name: Github Action for wget (argon1.sh)
|
||||||
uses: wei/wget@v1.1.1
|
uses: wei/wget@v1.1.1
|
||||||
with:
|
with:
|
||||||
args: https://download.argon40.com/argon1.sh -P ./download
|
args: https://download.argon40.com/argon1.sh -P ./download
|
||||||
- name: Github Action for wget (ar1config.png)
|
- name: Github Action for wget (argon1v5.sh)
|
||||||
uses: wei/wget@v1.1.1
|
uses: wei/wget@v1.1.1
|
||||||
with:
|
with:
|
||||||
args: http://download.argon40.com/ar1config.png -P ./download
|
args: https://download.argon40.com/argon1v5.sh -P ./download
|
||||||
- name: Github Action for wget (ar1uninstall.png)
|
- name: Github Action for wget (argon40.png)
|
||||||
uses: wei/wget@v1.1.1
|
uses: wei/wget@v1.1.1
|
||||||
with:
|
with:
|
||||||
args: http://download.argon40.com/ar1uninstall.png -P ./download
|
args: https://download.argon40.com/argon40.png -P ./download
|
||||||
|
- name: Github Action for wget (argon-eeprom.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/argon-eeprom.sh -P ./download
|
||||||
|
- name: Github Action for wget (argoneon.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/argoneon.png -P ./download
|
||||||
|
- name: Github Action for wget (argonone-irdecoder.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/argonone-irdecoder.py -P ./download
|
||||||
|
- name: Github Action for wget (argononeup.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/argononeup.sh -P ./download
|
||||||
|
- name: Github Action for wget (ArgonOne.uf2)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/firmware/ArgonOne.uf2 -P ./download/firmware
|
||||||
|
- name: Github Action for wget (bgcpu.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/bgcpu.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (bgdefault.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/bgdefault.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (bgip.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/bgip.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (bgraid.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/bgraid.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (bgram.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/bgram.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (bgstorage.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/bgstorage.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (bgtemp.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/bgtemp.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (bgtime.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/bgtime.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (font16x12.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/font16x12.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (font16x8.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/font16x8.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (font24x16.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/font24x16.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (font32x24.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/font32x24.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (font48x32.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/font48x32.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (font64x48.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/font64x48.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (font8x6.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/font8x6.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (logo1v5.bin)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/oled/logo1v5.bin -P ./download/oled
|
||||||
|
- name: Github Action for wget (argon-blstrdac.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argon-blstrdac.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argondashboard.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argondashboard.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argoneond.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argoneond.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argoneond.service)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argoneond.service -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argoneonoled.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argoneonoled.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argoneon-oledconfig.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argoneon-oledconfig.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argoneon-rtcconfig.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argoneon-rtcconfig.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonkeyboard.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonkeyboard.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononed.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononed.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononed.service)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononed.service -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonone-fanconfig.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonone-fanconfig.sh -P ./download/scripts
|
||||||
- name: Github Action for wget (argonone-irconfig.sh)
|
- name: Github Action for wget (argonone-irconfig.sh)
|
||||||
uses: wei/wget@v1.1.1
|
uses: wei/wget@v1.1.1
|
||||||
with:
|
with:
|
||||||
args: https://download.argon40.com/argonone-irconfig.sh -P ./download
|
args: https://download.argon40.com/scripts/argonone-irconfig.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonone-irdecoder-libgpiod.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonone-irdecoder-libgpiod.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononeoled.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononeoled.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonone-oledconfig.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonone-oledconfig.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononeoledd.service)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononeoledd.service -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononeupd.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononeupd.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononeupd.service)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononeupd.service -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononeupduser.service)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononeupduser.service -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononeup-lidconfig.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononeup-lidconfig.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonone-upsconfig.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonone-upsconfig.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononeupsd.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononeupsd.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argononeupsd.service)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argononeupsd.service -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonpowerbutton-libgpiod.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonpowerbutton-libgpiod.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonpowerbutton-rpigpio.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonpowerbutton-rpigpio.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonregister.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonregister.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonregister-v1.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonregister-v1.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argon-rpi-eeprom-config-default.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argon-rpi-eeprom-config-default.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argon-rpi-eeprom-config-psu.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argon-rpi-eeprom-config-psu.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonrtc.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonrtc.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argon-shutdown.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argon-shutdown.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonstatus.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonstatus.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argon-status.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argon-status.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonsysinfo.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonsysinfo.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argon-uninstall.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argon-uninstall.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argon-unitconfig.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argon-unitconfig.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonupsrtcd.py)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonupsrtcd.py -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argonupsrtcd.service)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argonupsrtcd.service -P ./download/scripts
|
||||||
|
- name: Github Action for wget (argon-versioninfo.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/scripts/argon-versioninfo.sh -P ./download/scripts
|
||||||
|
- name: Github Action for wget (setntpserver.sh)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/tools/setntpserver.sh -P ./download/tools
|
||||||
|
- name: Github Action for wget (battery_0.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_0.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (battery_1.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_1.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (battery_2.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_2.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (battery_3.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_3.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (battery_4.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_4.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (battery_alert.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_alert.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (battery_charging.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_charging.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (battery_plug.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_plug.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (battery_unknown.png)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/battery_unknown.png -P ./download/ups
|
||||||
|
- name: Github Action for wget (upsimg.tar.gz)
|
||||||
|
uses: wei/wget@v1.1.1
|
||||||
|
with:
|
||||||
|
args: https://download.argon40.com/ups/upsimg.tar.gz -P ./download/ups
|
||||||
- name: Delete ./source
|
- name: Delete ./source
|
||||||
run: rm -rf ./source
|
run: rm -rf ./source
|
||||||
- name: Rename ./download to ./source
|
- name: Rename ./download to ./source
|
||||||
run: mv ./download ./source
|
run: mv ./download ./source
|
||||||
# https://github.com/marketplace/actions/git-auto-commit
|
# https://github.com/marketplace/actions/git-auto-commit
|
||||||
- name: Git Auto Commit
|
- name: Git Auto Commit
|
||||||
uses: stefanzweifel/git-auto-commit-action@v4.16.0
|
uses: stefanzweifel/git-auto-commit-action@v6.0.1
|
||||||
with:
|
with:
|
||||||
commit_message: Automated Change by GitHub Action
|
commit_message: Automated Change by GitHub Action
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# Argon ONE (V2) Pi 4 Script
|
# Argon ONE Script
|
||||||
|
|
||||||
I have been using the [Argon ONE (V2) Case for Raspberry Pi 4](https://www.argon40.com/collections/raspberry-pi-cases "Argon ONE (V2) Case for Raspberry Pi 4") for a long time and I am very happy with it.
|
I have been using the [Argon ONE Cases for Raspberry Pi](https://www.argon40.com/collections/raspberry-pi-cases "Argon ONE Cases for Raspberry Pi") for a long time and I am very happy with them.
|
||||||
|
|
||||||
To be able to use the case to the full extent, it is recommended to install the [script](https://download.argon40.com/argon1.sh "https://download.argon40.com/argon1.sh") offered by [Argon 40](https://www.argon40.com "https://www.argon40.com").
|
To be able to use the cases to the full extent, it is recommended to install the [script](https://download.argon40.com/argon1.sh "https://download.argon40.com/argon1.sh") offered by [Argon 40](https://www.argon40.com "https://www.argon40.com").
|
||||||
|
|
||||||
I have saved a copy here along with the instructions to have a copy in case [Argon 40](https://www.argon40.com "https://www.argon40.com") no longer offers it themselves.
|
I have saved a copy here along with the instructions to have a copy in case [Argon 40](https://www.argon40.com "https://www.argon40.com") no longer offers it themselves.
|
||||||
|
|
||||||
@@ -13,19 +13,19 @@ You can find them here:
|
|||||||
* Argon 40 Website: [https://www.argon40.com](https://www.argon40.com "https://www.argon40.com")
|
* Argon 40 Website: [https://www.argon40.com](https://www.argon40.com "https://www.argon40.com")
|
||||||
* Argon 40 Github: [https://github.com/Argon40Tech](https://github.com/Argon40Tech "https://github.com/Argon40Tech")
|
* Argon 40 Github: [https://github.com/Argon40Tech](https://github.com/Argon40Tech "https://github.com/Argon40Tech")
|
||||||
|
|
||||||
## How to install Argon ONE (V2) Pi 4 Power Button & Fan Control
|
## How to install Argon ONE Pi Power Button & Fan Control
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
* [Raspberry Pi 4 Model B (2GB, 4GB or 8GB version)](https://www.raspberrypi.org/products/raspberry-pi-4-model-b/ "Raspberry Pi 4 Model B")
|
* [Raspberry Pi](https://www.raspberrypi.org/products/ "Raspberry Pi")
|
||||||
* [Raspberry Pi OS (previously called Raspbian)](https://www.raspberrypi.org/downloads/ "Raspberry Pi OS") installed on microSD card
|
* [Raspberry Pi OS (previously called Raspbian)](https://www.raspberrypi.org/downloads/ "Raspberry Pi OS") installed on microSD card
|
||||||
* [Argon ONE (V2) Case for Raspberry Pi 4](https://www.argon40.com/collections/raspberry-pi-cases "Argon ONE (V2) Case for Raspberry Pi 4")
|
* [Argon ONE Cases for Raspberry Pi](https://www.argon40.com/collections/raspberry-pi-cases "Argon ONE Cases for Raspberry Pi")
|
||||||
|
|
||||||
### Installing
|
### Installing
|
||||||
|
|
||||||
1. Connect to the internet.
|
1. Connect to the internet.
|
||||||
2. Open "Terminal" in Raspbian.
|
2. Open "Terminal" in Raspbian.
|
||||||
3. Type the text below in the "Terminal" to initiate installation of Argon ONE (V2) Pi 4 script.
|
3. Type the text below in the "Terminal" to initiate installation of Argon ONE Pi script.
|
||||||
|
|
||||||
```
|
```
|
||||||
curl https://download.argon40.com/argon1.sh | bash
|
curl https://download.argon40.com/argon1.sh | bash
|
||||||
@@ -35,9 +35,9 @@ You can find them here:
|
|||||||
|
|
||||||
## Usage Instructions
|
## Usage Instructions
|
||||||
|
|
||||||
### Argon ONE (V2) Pi 4 Power Button Functions
|
### Argon ONE Pi Power Button Functions
|
||||||
|
|
||||||
ARGON ONE (V2) PI 4 STATE | ACTION | FUNCTION
|
ARGON ONE PI STATE | ACTION | FUNCTION
|
||||||
:------------------: | :----: | :------:
|
:------------------: | :----: | :------:
|
||||||
OFF | Short Press | Turn ON
|
OFF | Short Press | Turn ON
|
||||||
ON | Long Press (>= 3 s) | Soft Shutdown and Power Cut
|
ON | Long Press (>= 3 s) | Soft Shutdown and Power Cut
|
||||||
@@ -45,8 +45,8 @@ ON | Short Press (< 3 s) | Nothing
|
|||||||
ON | Double Tap | Reboot
|
ON | Double Tap | Reboot
|
||||||
ON | Long Press (>= 5 s) | Forced Shutdown
|
ON | Long Press (>= 5 s) | Forced Shutdown
|
||||||
|
|
||||||
### Argon ONE (V2) Pi 4 Fan Speed
|
### Argon ONE Pi Fan Speed
|
||||||
Upon installation of the Argon ONE (V2) Pi 4 script by default, the settings of the Argon ONE (V2) Pi 4 cooling system are as follows:
|
Upon installation of the Argon ONE Pi script by default, the settings of the Argon ONE Pi cooling system are as follows:
|
||||||
|
|
||||||
CPU TEMP | FAN POWER
|
CPU TEMP | FAN POWER
|
||||||
:------: | :-------:
|
:------: | :-------:
|
||||||
@@ -54,7 +54,7 @@ CPU TEMP | FAN POWER
|
|||||||
60 C | 55%
|
60 C | 55%
|
||||||
65 C | 100%
|
65 C | 100%
|
||||||
|
|
||||||
However, you may change or configure the FAN to your desired settings by clicking the Argon ONE (V2) Pi 4 Config icon on your Desktop.
|
However, you may change or configure the FAN to your desired settings by clicking the Argon ONE Pi Config icon on your Desktop.
|
||||||
|
|
||||||
Or via "Terminal" by typing and following the specified format:
|
Or via "Terminal" by typing and following the specified format:
|
||||||
|
|
||||||
@@ -62,9 +62,9 @@ Or via "Terminal" by typing and following the specified format:
|
|||||||
argonone-config
|
argonone-config
|
||||||
```
|
```
|
||||||
|
|
||||||
## Uninstalling Argon ONE (V2) Pi 4 Script
|
## Uninstalling Argon ONE Pi Script
|
||||||
|
|
||||||
To uninstall the Argon ONE (V2) Pi 4 script you may do so by clicking the Argon One (V2) Pi 4 Uninstall icon on your Desktop.
|
To uninstall the Argon ONE Pi script you may do so by clicking the Argon One Pi Uninstall icon on your Desktop.
|
||||||
|
|
||||||
You may also remove the script via "Terminal" by typing.
|
You may also remove the script via "Terminal" by typing.
|
||||||
```
|
```
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 118 KiB |
@@ -0,0 +1,45 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "*************"
|
||||||
|
echo " Argon Setup "
|
||||||
|
echo "*************"
|
||||||
|
|
||||||
|
# Helper variables
|
||||||
|
ARGONDOWNLOADSERVER=https://download.argon40.com
|
||||||
|
|
||||||
|
eepromrpiscript="/usr/bin/rpi-eeprom-config"
|
||||||
|
eepromconfigscript=/dev/shm/argon-eeprom.py
|
||||||
|
|
||||||
|
# Check if Raspbian, Ubuntu, others
|
||||||
|
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"
|
||||||
|
elif [ "$ID" = "ubuntu" ]
|
||||||
|
then
|
||||||
|
CHECKPLATFORM="Ubuntu"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if original eeprom script exists before running
|
||||||
|
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
||||||
|
then
|
||||||
|
if [ -f "$eepromrpiscript" ]
|
||||||
|
then
|
||||||
|
sudo apt-get update && sudo apt-get upgrade -y
|
||||||
|
sudo rpi-eeprom-update
|
||||||
|
# EEPROM Config Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-rpi-eeprom-config-default.py -O $eepromconfigscript --quiet
|
||||||
|
sudo chmod 755 $eepromconfigscript
|
||||||
|
sudo $eepromconfigscript
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Please run this under Raspberry Pi OS"
|
||||||
|
fi
|
||||||
@@ -228,6 +228,8 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "Installing/updating dependencies..."
|
||||||
|
|
||||||
for curpkg in ${pkglist[@]}; do
|
for curpkg in ${pkglist[@]}; do
|
||||||
sudo apt-get install -y $curpkg
|
sudo apt-get install -y $curpkg
|
||||||
RESULT=$(argon_check_pkg "$curpkg")
|
RESULT=$(argon_check_pkg "$curpkg")
|
||||||
@@ -240,6 +242,8 @@ for curpkg in ${pkglist[@]}; do
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
echo "Updating configuration ..."
|
||||||
|
|
||||||
# Ubuntu Mate for RPi has raspi-config too
|
# Ubuntu Mate for RPi has raspi-config too
|
||||||
command -v raspi-config &> /dev/null
|
command -v raspi-config &> /dev/null
|
||||||
if [ $? -eq 0 ]
|
if [ $? -eq 0 ]
|
||||||
@@ -271,8 +275,9 @@ then
|
|||||||
rm $TMPCONFIGFILE
|
rm $TMPCONFIGFILE
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Added to enabled NVMe for pi5
|
# Additional config for pi5
|
||||||
set_nvme_default
|
set_nvme_default
|
||||||
|
set_maxusbcurrent
|
||||||
|
|
||||||
# Fan Setup
|
# Fan Setup
|
||||||
basename="argonone"
|
basename="argonone"
|
||||||
@@ -289,6 +294,7 @@ daemonfanservice=/lib/systemd/system/$daemonname.service
|
|||||||
|
|
||||||
daemonhddconfigfile=/etc/${daemonname}-hdd.conf
|
daemonhddconfigfile=/etc/${daemonname}-hdd.conf
|
||||||
|
|
||||||
|
echo "Installing/Updating scripts and services ..."
|
||||||
|
|
||||||
if [ -f "$eepromrpiscript" ]
|
if [ -f "$eepromrpiscript" ]
|
||||||
then
|
then
|
||||||
@@ -304,6 +310,13 @@ then
|
|||||||
sudo chmod 755 $upsconfigscript
|
sudo chmod 755 $upsconfigscript
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
for TMPDIRECTORY in "/lib/systemd/system" "/lib/systemd/system-shutdown"
|
||||||
|
do
|
||||||
|
sudo mkdir -p "$TMPDIRECTORY"
|
||||||
|
sudo chmod 755 $TMPDIRECTORY
|
||||||
|
sudo chown root:root "$TMPDIRECTORY"
|
||||||
|
done
|
||||||
|
|
||||||
# Fan Config Script
|
# Fan Config Script
|
||||||
sudo wget $ARGONDOWNLOADSERVER/scripts/argonone-fanconfig.sh -O $fanconfigscript --quiet
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonone-fanconfig.sh -O $fanconfigscript --quiet
|
||||||
sudo chmod 755 $fanconfigscript
|
sudo chmod 755 $fanconfigscript
|
||||||
@@ -705,6 +718,8 @@ fi
|
|||||||
shortcutfile="/home/$destfoldername/Desktop/argonone-config.desktop"
|
shortcutfile="/home/$destfoldername/Desktop/argonone-config.desktop"
|
||||||
if [ -d "/home/$destfoldername/Desktop" ]
|
if [ -d "/home/$destfoldername/Desktop" ]
|
||||||
then
|
then
|
||||||
|
echo "Creating/Updating Desktop Elements ..."
|
||||||
|
|
||||||
terminalcmd="lxterminal --working-directory=/home/$destfoldername/ -t"
|
terminalcmd="lxterminal --working-directory=/home/$destfoldername/ -t"
|
||||||
if [ -f "/home/$destfoldername/.twisteros.twid" ]
|
if [ -f "/home/$destfoldername/.twisteros.twid" ]
|
||||||
then
|
then
|
||||||
@@ -735,6 +750,8 @@ fi
|
|||||||
|
|
||||||
configcmd="$(basename -- $configscript)"
|
configcmd="$(basename -- $configscript)"
|
||||||
|
|
||||||
|
echo "Initializing Services ..."
|
||||||
|
|
||||||
if [ "$setupmode" = "Setup" ]
|
if [ "$setupmode" = "Setup" ]
|
||||||
then
|
then
|
||||||
if [ -f "/usr/bin/$configcmd" ]
|
if [ -f "/usr/bin/$configcmd" ]
|
||||||
@@ -772,10 +789,12 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
||||||
then
|
then
|
||||||
if [ -f "$eepromrpiscript" ]
|
if [ -f "$eepromrpiscript" ]
|
||||||
then
|
then
|
||||||
|
echo "Checking EEPROM ..."
|
||||||
sudo apt-get update && sudo apt-get upgrade -y
|
sudo apt-get update && sudo apt-get upgrade -y
|
||||||
sudo rpi-eeprom-update
|
sudo rpi-eeprom-update
|
||||||
# EEPROM Config Script
|
# EEPROM Config Script
|
||||||
@@ -785,8 +804,6 @@ else
|
|||||||
echo "WARNING: EEPROM not updated. Please run this under Raspberry Pi OS"
|
echo "WARNING: EEPROM not updated. Please run this under Raspberry Pi OS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set_maxusbcurrent
|
|
||||||
|
|
||||||
|
|
||||||
echo "*********************"
|
echo "*********************"
|
||||||
echo " $setupmode Completed "
|
echo " $setupmode Completed "
|
||||||
|
|||||||
@@ -0,0 +1,822 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "*************"
|
||||||
|
echo " Argon Setup "
|
||||||
|
echo "*************"
|
||||||
|
|
||||||
|
|
||||||
|
# Check time if need to 'fix'
|
||||||
|
NEEDSTIMESYNC=0
|
||||||
|
LOCALTIME=$(date -u +%s%N | cut -b1-10)
|
||||||
|
GLOBALTIME=$(curl -s 'http://worldtimeapi.org/api/ip.txt' | grep unixtime | cut -b11-20)
|
||||||
|
TIMEDIFF=$((GLOBALTIME-LOCALTIME))
|
||||||
|
|
||||||
|
# about 26hrs, max timezone difference
|
||||||
|
if [ $TIMEDIFF -gt 100000 ]
|
||||||
|
then
|
||||||
|
NEEDSTIMESYNC=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
argon_time_error() {
|
||||||
|
echo "**********************************************"
|
||||||
|
echo "* WARNING: Device time seems to be incorrect *"
|
||||||
|
echo "* This may cause problems during setup. *"
|
||||||
|
echo "**********************************************"
|
||||||
|
echo "Possible Network Time Protocol Server issue"
|
||||||
|
echo "Try running the following to correct:"
|
||||||
|
echo " curl -k https://download.argon40.com/tools/setntpserver.sh | bash"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $NEEDSTIMESYNC -eq 1 ]
|
||||||
|
then
|
||||||
|
argon_time_error
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Helper variables
|
||||||
|
ARGONDOWNLOADSERVER=https://download.argon40.com
|
||||||
|
|
||||||
|
INSTALLATIONFOLDER=/etc/argon
|
||||||
|
|
||||||
|
FLAGFILEV1=$INSTALLATIONFOLDER/flag_v1
|
||||||
|
|
||||||
|
versioninfoscript=$INSTALLATIONFOLDER/argon-versioninfo.sh
|
||||||
|
|
||||||
|
uninstallscript=$INSTALLATIONFOLDER/argon-uninstall.sh
|
||||||
|
shutdownscript=/lib/systemd/system-shutdown/argon-shutdown.sh
|
||||||
|
configscript=$INSTALLATIONFOLDER/argon-config
|
||||||
|
unitconfigscript=$INSTALLATIONFOLDER/argon-unitconfig.sh
|
||||||
|
blstrdacconfigscript=$INSTALLATIONFOLDER/argon-blstrdac.sh
|
||||||
|
statusdisplayscript=$INSTALLATIONFOLDER/argon-status.sh
|
||||||
|
|
||||||
|
setupmode="Setup"
|
||||||
|
|
||||||
|
if [ -f $configscript ]
|
||||||
|
then
|
||||||
|
setupmode="Update"
|
||||||
|
echo "Updating files"
|
||||||
|
else
|
||||||
|
sudo mkdir $INSTALLATIONFOLDER
|
||||||
|
sudo chmod 755 $INSTALLATIONFOLDER
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Start code lifted from raspi-config
|
||||||
|
# is_pifive, get_serial_hw and do_serial_hw based on raspi-config
|
||||||
|
|
||||||
|
if [ -e /boot/firmware/config.txt ] ; then
|
||||||
|
FIRMWARE=/firmware
|
||||||
|
else
|
||||||
|
FIRMWARE=
|
||||||
|
fi
|
||||||
|
CONFIG=/boot${FIRMWARE}/config.txt
|
||||||
|
|
||||||
|
set_config_var() {
|
||||||
|
if ! grep -q -E "$1=$2" $3 ; then
|
||||||
|
echo "$1=$2" | sudo tee -a $3 > /dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
is_pifive() {
|
||||||
|
grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F]4[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$" /proc/cpuinfo
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get_serial_hw() {
|
||||||
|
if is_pifive ; then
|
||||||
|
if grep -q -E "dtparam=uart0=off" $CONFIG ; then
|
||||||
|
echo 1
|
||||||
|
elif grep -q -E "dtparam=uart0" $CONFIG ; then
|
||||||
|
echo 0
|
||||||
|
else
|
||||||
|
echo 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if grep -q -E "^enable_uart=1" $CONFIG ; then
|
||||||
|
echo 0
|
||||||
|
elif grep -q -E "^enable_uart=0" $CONFIG ; then
|
||||||
|
echo 1
|
||||||
|
elif [ -e /dev/serial0 ] ; then
|
||||||
|
echo 0
|
||||||
|
else
|
||||||
|
echo 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
do_serial_hw() {
|
||||||
|
if [ $1 -eq 0 ] ; then
|
||||||
|
if is_pifive ; then
|
||||||
|
set_config_var dtparam=uart0 on $CONFIG
|
||||||
|
else
|
||||||
|
set_config_var enable_uart 1 $CONFIG
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if is_pifive ; then
|
||||||
|
sudo sed $CONFIG -i -e "/dtparam=uart0.*/d"
|
||||||
|
else
|
||||||
|
set_config_var enable_uart 0 $CONFIG
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# End code lifted from raspi-config
|
||||||
|
##########
|
||||||
|
|
||||||
|
# Reuse is_pifive, set_config_var
|
||||||
|
set_nvme_default() {
|
||||||
|
if is_pifive ; then
|
||||||
|
set_config_var dtparam nvme $CONFIG
|
||||||
|
set_config_var dtparam=pciex1_gen 3 $CONFIG
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
set_maxusbcurrent() {
|
||||||
|
if is_pifive ; then
|
||||||
|
#set_config_var max_usb_current 1 $CONFIG
|
||||||
|
set_config_var usb_max_current_enable 1 $CONFIG
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
argon_check_pkg() {
|
||||||
|
RESULT=$(dpkg-query -W -f='${Status}\n' "$1" 2> /dev/null | grep "installed")
|
||||||
|
|
||||||
|
if [ "" == "$RESULT" ]; then
|
||||||
|
echo "NG"
|
||||||
|
else
|
||||||
|
echo "OK"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CHECKDEVICE="oneoled" # Hardcoded for argon1oled
|
||||||
|
# Check if has RTC
|
||||||
|
# Todo for multiple OS
|
||||||
|
|
||||||
|
#i2cdetect -y 1 | grep -q ' 51 '
|
||||||
|
#if [ $? -eq 0 ]
|
||||||
|
#then
|
||||||
|
# CHECKDEVICE="eon"
|
||||||
|
#fi
|
||||||
|
|
||||||
|
CHECKGPIOMODE="libgpiod" # libgpiod 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
|
||||||
|
|
||||||
|
gpiopkg="python3-libgpiod"
|
||||||
|
if [ "$CHECKGPIOMODE" = "rpigpio" ]
|
||||||
|
then
|
||||||
|
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
||||||
|
then
|
||||||
|
gpiopkg="raspi-gpio python3-rpi.gpio"
|
||||||
|
else
|
||||||
|
gpiopkg="python3-rpi.gpio"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
||||||
|
then
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
pkglist=($gpiopkg python3-smbus i2c-tools smartmontools)
|
||||||
|
elif [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
pkglist=($gpiopkg python3-smbus i2c-tools python3-luma.oled)
|
||||||
|
else
|
||||||
|
pkglist=($gpiopkg python3-smbus i2c-tools)
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Todo handle lgpio
|
||||||
|
# Ubuntu has serial and i2c enabled
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
pkglist=($gpiopkg python3-smbus i2c-tools smartmontools)
|
||||||
|
elif [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
pkglist=($gpiopkg python3-smbus i2c-tools python3-luma.oled)
|
||||||
|
else
|
||||||
|
pkglist=($gpiopkg python3-smbus i2c-tools)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Installing/updating dependencies..."
|
||||||
|
|
||||||
|
for curpkg in ${pkglist[@]}; do
|
||||||
|
sudo apt-get install -y $curpkg
|
||||||
|
RESULT=$(argon_check_pkg "$curpkg")
|
||||||
|
if [ "NG" == "$RESULT" ]
|
||||||
|
then
|
||||||
|
echo "********************************************************************"
|
||||||
|
echo "Please also connect device to the internet and restart installation."
|
||||||
|
echo "********************************************************************"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Updating configuration ..."
|
||||||
|
|
||||||
|
# Ubuntu Mate for RPi has raspi-config too
|
||||||
|
command -v raspi-config &> /dev/null
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
# Enable i2c and serial
|
||||||
|
sudo raspi-config nonint do_i2c 0
|
||||||
|
if [ ! "$CHECKDEVICE" = "fanhat" ]
|
||||||
|
then
|
||||||
|
|
||||||
|
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
||||||
|
then
|
||||||
|
# bookworm raspi-config prompts user when configuring serial
|
||||||
|
if [ $(get_serial_hw) -eq 1 ]; then
|
||||||
|
do_serial_hw 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
sudo raspi-config nonint do_serial 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
TMPCONFIGFILE="/dev/shm/tmpconfig.txt"
|
||||||
|
cat $CONFIG | grep -v 'dtoverlay=dwc2' > $TMPCONFIGFILE
|
||||||
|
chmod 755 $TMPCONFIGFILE
|
||||||
|
sudo cp $TMPCONFIGFILE $CONFIG
|
||||||
|
set_config_var dtoverlay=dwc2,dr_mode host $CONFIG
|
||||||
|
rm $TMPCONFIGFILE
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Additional config for pi5
|
||||||
|
set_nvme_default
|
||||||
|
set_maxusbcurrent
|
||||||
|
|
||||||
|
# Fan Setup
|
||||||
|
basename="argonone"
|
||||||
|
daemonname=$basename"d"
|
||||||
|
irconfigscript=$INSTALLATIONFOLDER/${basename}-ir
|
||||||
|
upsconfigscript=$INSTALLATIONFOLDER/${basename}-upsconfig.sh
|
||||||
|
fanconfigscript=$INSTALLATIONFOLDER/${basename}-fanconfig.sh
|
||||||
|
eepromrpiscript="/usr/bin/rpi-eeprom-config"
|
||||||
|
eepromconfigscript=$INSTALLATIONFOLDER/${basename}-eepromconfig.py
|
||||||
|
powerbuttonscript=$INSTALLATIONFOLDER/$daemonname.py
|
||||||
|
unitconfigfile=/etc/argonunits.conf
|
||||||
|
daemonconfigfile=/etc/$daemonname.conf
|
||||||
|
daemonfanservice=/lib/systemd/system/$daemonname.service
|
||||||
|
|
||||||
|
daemonhddconfigfile=/etc/${daemonname}-hdd.conf
|
||||||
|
|
||||||
|
echo "Installing/Updating scripts and services ..."
|
||||||
|
|
||||||
|
if [ -f "$eepromrpiscript" ]
|
||||||
|
then
|
||||||
|
# EEPROM Config Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-rpi-eeprom-config-psu.py -O $eepromconfigscript --quiet
|
||||||
|
sudo chmod 755 $eepromconfigscript
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_pifive
|
||||||
|
then
|
||||||
|
# UPS Config Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonone-upsconfig.sh -O $upsconfigscript --quiet
|
||||||
|
sudo chmod 755 $upsconfigscript
|
||||||
|
fi
|
||||||
|
|
||||||
|
for TMPDIRECTORY in "/lib/systemd/system" "/lib/systemd/system-shutdown"
|
||||||
|
do
|
||||||
|
sudo mkdir -p "$TMPDIRECTORY"
|
||||||
|
sudo chmod 755 $TMPDIRECTORY
|
||||||
|
sudo chown root:root "$TMPDIRECTORY"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Fan Config Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonone-fanconfig.sh -O $fanconfigscript --quiet
|
||||||
|
sudo chmod 755 $fanconfigscript
|
||||||
|
|
||||||
|
|
||||||
|
# Fan Daemon/Service Files
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argononed.py -O $powerbuttonscript --quiet
|
||||||
|
if [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argononeoledd.service -O $daemonfanservice --quiet
|
||||||
|
else
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argononed.service -O $daemonfanservice --quiet
|
||||||
|
fi
|
||||||
|
sudo chmod 644 $daemonfanservice
|
||||||
|
|
||||||
|
if [ ! "$CHECKDEVICE" = "fanhat" ]
|
||||||
|
then
|
||||||
|
# IR Files
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonone-irconfig.sh -O $irconfigscript --quiet
|
||||||
|
sudo chmod 755 $irconfigscript
|
||||||
|
|
||||||
|
if [ ! "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-blstrdac.sh -O $blstrdacconfigscript --quiet
|
||||||
|
sudo chmod 755 $blstrdacconfigscript
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Other utility scripts
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonstatus.py -O $INSTALLATIONFOLDER/argonstatus.py --quiet
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argondashboard.py -O $INSTALLATIONFOLDER/argondashboard.py --quiet
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-status.sh -O $statusdisplayscript --quiet
|
||||||
|
sudo chmod 755 $statusdisplayscript
|
||||||
|
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-versioninfo.sh -O $versioninfoscript --quiet
|
||||||
|
sudo chmod 755 $versioninfoscript
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonsysinfo.py -O $INSTALLATIONFOLDER/argonsysinfo.py --quiet
|
||||||
|
|
||||||
|
if [ -f "$FLAGFILEV1" ]
|
||||||
|
then
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonregister-v1.py -O $INSTALLATIONFOLDER/argonregister.py --quiet
|
||||||
|
else
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonregister.py -O $INSTALLATIONFOLDER/argonregister.py --quiet
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo wget "$ARGONDOWNLOADSERVER/scripts/argonpowerbutton-${CHECKGPIOMODE}.py" -O $INSTALLATIONFOLDER/argonpowerbutton.py --quiet
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argononed.py -O $powerbuttonscript --quiet
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-unitconfig.sh -O $unitconfigscript --quiet
|
||||||
|
sudo chmod 755 $unitconfigscript
|
||||||
|
|
||||||
|
|
||||||
|
# Generate default Fan config file if non-existent
|
||||||
|
if [ ! -f $daemonconfigfile ]; then
|
||||||
|
sudo touch $daemonconfigfile
|
||||||
|
sudo chmod 666 $daemonconfigfile
|
||||||
|
|
||||||
|
echo '#' >> $daemonconfigfile
|
||||||
|
echo '# Argon Fan Speed Configuration (CPU)' >> $daemonconfigfile
|
||||||
|
echo '#' >> $daemonconfigfile
|
||||||
|
echo '55=30' >> $daemonconfigfile
|
||||||
|
echo '60=55' >> $daemonconfigfile
|
||||||
|
echo '65=100' >> $daemonconfigfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
if [ ! -f $daemonhddconfigfile ]; then
|
||||||
|
sudo touch $daemonhddconfigfile
|
||||||
|
sudo chmod 666 $daemonhddconfigfile
|
||||||
|
|
||||||
|
echo '#' >> $daemonhddconfigfile
|
||||||
|
echo '# Argon Fan Speed Configuration (HDD)' >> $daemonhddconfigfile
|
||||||
|
echo '#' >> $daemonhddconfigfile
|
||||||
|
echo '35=30' >> $daemonhddconfigfile
|
||||||
|
echo '40=55' >> $daemonhddconfigfile
|
||||||
|
echo '45=100' >> $daemonhddconfigfile
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate default Unit config file if non-existent
|
||||||
|
if [ ! -f $unitconfigfile ]; then
|
||||||
|
sudo touch $unitconfigfile
|
||||||
|
sudo chmod 666 $unitconfigfile
|
||||||
|
|
||||||
|
echo '#' >> $unitconfigfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
# RTC Setup
|
||||||
|
basename="argoneon"
|
||||||
|
daemonname=$basename"d"
|
||||||
|
|
||||||
|
rtcconfigfile=/etc/argoneonrtc.conf
|
||||||
|
rtcconfigscript=$INSTALLATIONFOLDER/${basename}-rtcconfig.sh
|
||||||
|
daemonrtcservice=/lib/systemd/system/$daemonname.service
|
||||||
|
rtcdaemonscript=$INSTALLATIONFOLDER/$daemonname.py
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# RTC Config Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argoneon-rtcconfig.sh -O $rtcconfigscript --quiet
|
||||||
|
sudo chmod 755 $rtcconfigscript
|
||||||
|
|
||||||
|
# RTC Daemon/Service Files
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonrtc.py -O $INSTALLATIONFOLDER/argonrtc.py --quiet
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argoneond.py -O $rtcdaemonscript --quiet
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argoneond.service -O $daemonrtcservice --quiet
|
||||||
|
sudo chmod 644 $daemonrtcservice
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ] || [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
# OLED Setup
|
||||||
|
basename="argoneon"
|
||||||
|
daemonname=$basename"d"
|
||||||
|
|
||||||
|
oledconfigscript=$INSTALLATIONFOLDER/${basename}-oledconfig.sh
|
||||||
|
oledlibscript=$INSTALLATIONFOLDER/${basename}oled.py
|
||||||
|
oledconfigfile=/etc/argoneonoled.conf
|
||||||
|
|
||||||
|
# Generate default OLED config file if non-existent
|
||||||
|
if [ ! -f $oledconfigfile ]; then
|
||||||
|
sudo touch $oledconfigfile
|
||||||
|
sudo chmod 666 $oledconfigfile
|
||||||
|
|
||||||
|
echo '#' >> $oledconfigfile
|
||||||
|
echo '# Argon OLED Configuration' >> $oledconfigfile
|
||||||
|
echo '#' >> $oledconfigfile
|
||||||
|
echo 'switchduration=30' >> $oledconfigfile
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
echo 'screenlist="clock cpu storage raid ram temp ip"' >> $oledconfigfile
|
||||||
|
else
|
||||||
|
echo 'screenlist="logo1v5 clock cpu storage ram temp ip"' >> $oledconfigfile
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# OLED Config Script
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argoneonoled.py -O $oledlibscript --quiet
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argoneon-oledconfig.sh -O $oledconfigscript --quiet
|
||||||
|
else
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argononeoled.py -O $oledlibscript --quiet
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonone-oledconfig.sh -O $oledconfigscript --quiet
|
||||||
|
fi
|
||||||
|
sudo chmod 755 $oledconfigscript
|
||||||
|
|
||||||
|
if [ ! -d $INSTALLATIONFOLDER/oled ]
|
||||||
|
then
|
||||||
|
sudo mkdir $INSTALLATIONFOLDER/oled
|
||||||
|
fi
|
||||||
|
|
||||||
|
for binfile in font8x6 font16x12 font32x24 font64x48 font16x8 font24x16 font48x32 bgdefault bgram bgip bgtemp bgcpu bgraid bgstorage bgtime
|
||||||
|
do
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/oled/${binfile}.bin -O $INSTALLATIONFOLDER/oled/${binfile}.bin --quiet
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
for binfile in logo1v5
|
||||||
|
do
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/oled/${binfile}.bin -O $INSTALLATIONFOLDER/oled/${binfile}.bin --quiet
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Argon Uninstall Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-uninstall.sh -O $uninstallscript --quiet
|
||||||
|
sudo chmod 755 $uninstallscript
|
||||||
|
|
||||||
|
# Argon Shutdown script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-shutdown.sh -O $shutdownscript --quiet
|
||||||
|
sudo chmod 755 $shutdownscript
|
||||||
|
|
||||||
|
# Argon Config Script
|
||||||
|
if [ -f $configscript ]; then
|
||||||
|
sudo rm $configscript
|
||||||
|
fi
|
||||||
|
sudo touch $configscript
|
||||||
|
|
||||||
|
# To ensure we can write the following lines
|
||||||
|
sudo chmod 666 $configscript
|
||||||
|
|
||||||
|
echo '#!/bin/bash' >> $configscript
|
||||||
|
|
||||||
|
echo 'echo "--------------------------"' >> $configscript
|
||||||
|
echo 'echo "Argon Configuration Tool"' >> $configscript
|
||||||
|
echo "$versioninfoscript simple" >> $configscript
|
||||||
|
echo 'echo "--------------------------"' >> $configscript
|
||||||
|
|
||||||
|
echo 'get_number () {' >> $configscript
|
||||||
|
echo ' read curnumber' >> $configscript
|
||||||
|
echo ' if [ -z "$curnumber" ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' echo "-2"' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo ' elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' if [ $curnumber -lt 0 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' echo "-1"' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo ' elif [ $curnumber -gt 100 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' echo "-1"' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo ' fi ' >> $configscript
|
||||||
|
echo ' echo $curnumber' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo ' fi' >> $configscript
|
||||||
|
echo ' echo "-1"' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo '}' >> $configscript
|
||||||
|
echo '' >> $configscript
|
||||||
|
|
||||||
|
echo 'mainloopflag=1' >> $configscript
|
||||||
|
echo 'while [ $mainloopflag -eq 1 ]' >> $configscript
|
||||||
|
echo 'do' >> $configscript
|
||||||
|
echo ' echo' >> $configscript
|
||||||
|
echo ' echo "Choose Option:"' >> $configscript
|
||||||
|
if [ ! "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
echo ' echo " 1. Configure Fan"' >> $configscript
|
||||||
|
fi
|
||||||
|
|
||||||
|
blstrdacoption=0
|
||||||
|
|
||||||
|
if [ "$CHECKDEVICE" = "fanhat" ]
|
||||||
|
then
|
||||||
|
uninstalloption="4"
|
||||||
|
else
|
||||||
|
if [ ! "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
echo ' echo " 2. Configure IR"' >> $configscript
|
||||||
|
fi
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
# ArgonEON Has RTC
|
||||||
|
echo ' echo " 3. Configure RTC and/or Schedule"' >> $configscript
|
||||||
|
echo ' echo " 4. Configure OLED"' >> $configscript
|
||||||
|
uninstalloption="7"
|
||||||
|
elif [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
echo ' echo " 1. Configure OLED"' >> $configscript
|
||||||
|
echo ' echo " 2. Argon Industria UPS"' >> $configscript
|
||||||
|
uninstalloption="5"
|
||||||
|
elif is_pifive
|
||||||
|
then
|
||||||
|
echo ' echo " 3. Argon Industria UPS"' >> $configscript
|
||||||
|
uninstalloption="7"
|
||||||
|
blstrdacoption=$(($uninstalloption-3))
|
||||||
|
echo " echo \" $blstrdacoption. Configure BLSTR DAC (v3/v5 only)\"" >> $configscript
|
||||||
|
else
|
||||||
|
uninstalloption="6"
|
||||||
|
blstrdacoption=$(($uninstalloption-3))
|
||||||
|
echo " echo \" $blstrdacoption. Configure BLSTR DAC (v3 only)\"" >> $configscript
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
unitsoption=$(($uninstalloption-2))
|
||||||
|
echo " echo \" $unitsoption. Configure Units\"" >> $configscript
|
||||||
|
statusoption=$(($uninstalloption-1))
|
||||||
|
echo " echo \" $statusoption. System Information\"" >> $configscript
|
||||||
|
|
||||||
|
echo " echo \" $uninstalloption. Uninstall\"" >> $configscript
|
||||||
|
echo ' echo ""' >> $configscript
|
||||||
|
echo ' echo " 0. Exit"' >> $configscript
|
||||||
|
echo " echo -n \"Enter Number (0-$uninstalloption):\"" >> $configscript
|
||||||
|
echo ' newmode=$( get_number )' >> $configscript
|
||||||
|
|
||||||
|
|
||||||
|
echo ' if [ $newmode -eq 0 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' echo "Thank you."' >> $configscript
|
||||||
|
echo ' mainloopflag=0' >> $configscript
|
||||||
|
echo ' elif [ $newmode -eq 1 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
|
||||||
|
# Option 1
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
echo ' echo "Choose Triggers:"' >> $configscript
|
||||||
|
echo ' echo " 1. CPU Temperature"' >> $configscript
|
||||||
|
echo ' echo " 2. HDD Temperature"' >> $configscript
|
||||||
|
echo ' echo ""' >> $configscript
|
||||||
|
echo ' echo " 0. Cancel"' >> $configscript
|
||||||
|
echo " echo -n \"Enter Number (0-2):\"" >> $configscript
|
||||||
|
echo ' submode=$( get_number )' >> $configscript
|
||||||
|
|
||||||
|
echo ' if [ $submode -eq 1 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $fanconfigscript" >> $configscript
|
||||||
|
echo ' mainloopflag=0' >> $configscript
|
||||||
|
echo ' elif [ $submode -eq 2 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $fanconfigscript hdd" >> $configscript
|
||||||
|
echo ' mainloopflag=0' >> $configscript
|
||||||
|
echo ' fi' >> $configscript
|
||||||
|
elif [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
echo " $oledconfigscript" >> $configscript
|
||||||
|
echo ' mainloopflag=0' >> $configscript
|
||||||
|
else
|
||||||
|
echo " $fanconfigscript" >> $configscript
|
||||||
|
echo ' mainloopflag=0' >> $configscript
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Options 2 onwards
|
||||||
|
if [ ! "$CHECKDEVICE" = "fanhat" ]
|
||||||
|
then
|
||||||
|
if [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
echo ' elif [ $newmode -eq 2 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $upsconfigscript" >> $configscript
|
||||||
|
#echo ' mainloopflag=0' >> $configscript
|
||||||
|
|
||||||
|
else
|
||||||
|
echo ' elif [ $newmode -eq 2 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $irconfigscript" >> $configscript
|
||||||
|
#echo ' mainloopflag=0' >> $configscript
|
||||||
|
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
echo ' elif [ $newmode -eq 3 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $rtcconfigscript" >> $configscript
|
||||||
|
#echo ' mainloopflag=0' >> $configscript
|
||||||
|
echo ' elif [ $newmode -eq 4 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $oledconfigscript" >> $configscript
|
||||||
|
#echo ' mainloopflag=0' >> $configscript
|
||||||
|
elif is_pifive
|
||||||
|
then
|
||||||
|
echo ' elif [ $newmode -eq 3 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $upsconfigscript" >> $configscript
|
||||||
|
#echo ' mainloopflag=0' >> $configscript
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $blstrdacoption -gt 0 ]
|
||||||
|
then
|
||||||
|
echo " elif [ \$newmode -eq $blstrdacoption ]" >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $blstrdacconfigscript" >> $configscript
|
||||||
|
#echo ' mainloopflag=0' >> $configscript
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Standard options
|
||||||
|
echo " elif [ \$newmode -eq $unitsoption ]" >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $unitconfigscript" >> $configscript
|
||||||
|
#echo ' mainloopflag=0' >> $configscript
|
||||||
|
|
||||||
|
echo " elif [ \$newmode -eq $statusoption ]" >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $statusdisplayscript" >> $configscript
|
||||||
|
|
||||||
|
echo " elif [ \$newmode -eq $uninstalloption ]" >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $uninstallscript" >> $configscript
|
||||||
|
echo ' mainloopflag=0' >> $configscript
|
||||||
|
echo ' fi' >> $configscript
|
||||||
|
echo 'done' >> $configscript
|
||||||
|
|
||||||
|
sudo chmod 755 $configscript
|
||||||
|
|
||||||
|
# Desktop Icon
|
||||||
|
destfoldername=$USERNAME
|
||||||
|
if [ -z "$destfoldername" ]
|
||||||
|
then
|
||||||
|
destfoldername=$USER
|
||||||
|
fi
|
||||||
|
if [ -z "$destfoldername" ]
|
||||||
|
then
|
||||||
|
destfoldername="pi"
|
||||||
|
fi
|
||||||
|
|
||||||
|
shortcutfile="/home/$destfoldername/Desktop/argonone-config.desktop"
|
||||||
|
if [ -d "/home/$destfoldername/Desktop" ]
|
||||||
|
then
|
||||||
|
echo "Creating/Updating Desktop Elements ..."
|
||||||
|
|
||||||
|
terminalcmd="lxterminal --working-directory=/home/$destfoldername/ -t"
|
||||||
|
if [ -f "/home/$destfoldername/.twisteros.twid" ]
|
||||||
|
then
|
||||||
|
terminalcmd="xfce4-terminal --default-working-directory=/home/$destfoldername/ -T"
|
||||||
|
fi
|
||||||
|
imagefile=ar1config.png
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
imagefile=argoneon.png
|
||||||
|
fi
|
||||||
|
sudo wget https://download.argon40.com/$imagefile -O /usr/share/pixmaps/$imagefile --quiet
|
||||||
|
if [ -f $shortcutfile ]; then
|
||||||
|
sudo rm $shortcutfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create Shortcuts
|
||||||
|
echo "[Desktop Entry]" > $shortcutfile
|
||||||
|
echo "Name=Argon Configuration" >> $shortcutfile
|
||||||
|
echo "Comment=Argon Configuration" >> $shortcutfile
|
||||||
|
echo "Icon=/usr/share/pixmaps/$imagefile" >> $shortcutfile
|
||||||
|
echo 'Exec='$terminalcmd' "Argon Configuration" -e '$configscript >> $shortcutfile
|
||||||
|
echo "Type=Application" >> $shortcutfile
|
||||||
|
echo "Encoding=UTF-8" >> $shortcutfile
|
||||||
|
echo "Terminal=false" >> $shortcutfile
|
||||||
|
echo "Categories=None;" >> $shortcutfile
|
||||||
|
chmod 755 $shortcutfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
configcmd="$(basename -- $configscript)"
|
||||||
|
|
||||||
|
echo "Initializing Services ..."
|
||||||
|
|
||||||
|
if [ "$setupmode" = "Setup" ]
|
||||||
|
then
|
||||||
|
if [ -f "/usr/bin/$configcmd" ]
|
||||||
|
then
|
||||||
|
sudo rm /usr/bin/$configcmd
|
||||||
|
fi
|
||||||
|
sudo ln -s $configscript /usr/bin/$configcmd
|
||||||
|
|
||||||
|
if [ "$CHECKDEVICE" = "one" ] || [ "$CHECKDEVICE" = "oneoled" ]
|
||||||
|
then
|
||||||
|
sudo ln -s $configscript /usr/bin/argonone-config
|
||||||
|
sudo ln -s $uninstallscript /usr/bin/argonone-uninstall
|
||||||
|
sudo ln -s $irconfigscript /usr/bin/argonone-ir
|
||||||
|
elif [ "$CHECKDEVICE" = "fanhat" ]
|
||||||
|
then
|
||||||
|
sudo ln -s $configscript /usr/bin/argonone-config
|
||||||
|
sudo ln -s $uninstallscript /usr/bin/argonone-uninstall
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable and Start Service(s)
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable argononed.service
|
||||||
|
sudo systemctl start argononed.service
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
sudo systemctl enable argoneond.service
|
||||||
|
sudo systemctl start argoneond.service
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl restart argononed.service
|
||||||
|
if [ "$CHECKDEVICE" = "eon" ]
|
||||||
|
then
|
||||||
|
sudo systemctl restart argoneond.service
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
||||||
|
then
|
||||||
|
if [ -f "$eepromrpiscript" ]
|
||||||
|
then
|
||||||
|
echo "Checking EEPROM ..."
|
||||||
|
sudo apt-get update && sudo apt-get upgrade -y
|
||||||
|
sudo rpi-eeprom-update
|
||||||
|
# EEPROM Config Script
|
||||||
|
sudo $eepromconfigscript
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARNING: EEPROM not updated. Please run this under Raspberry Pi OS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "*********************"
|
||||||
|
echo " $setupmode Completed "
|
||||||
|
echo "*********************"
|
||||||
|
$versioninfoscript
|
||||||
|
echo
|
||||||
|
echo "Use '$configcmd' to configure device"
|
||||||
|
echo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if [ $NEEDSTIMESYNC -eq 1 ]
|
||||||
|
then
|
||||||
|
argon_time_error
|
||||||
|
fi
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 700 B |
|
After Width: | Height: | Size: 30 KiB |
@@ -0,0 +1,514 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
# Standard Headers
|
||||||
|
import sys
|
||||||
|
import smbus
|
||||||
|
|
||||||
|
# For GPIO
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Check if Lirc Lib is installed
|
||||||
|
haslirclib = os.path.isfile("/usr/bin/mode2")
|
||||||
|
if haslirclib == True:
|
||||||
|
from multiprocessing import Process
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# Use GPIO
|
||||||
|
|
||||||
|
def getGPIOPulseData():
|
||||||
|
irreceiver_pin = 23 # IR Receiver Pin
|
||||||
|
GPIO.setmode(GPIO.BCM)
|
||||||
|
GPIO.setup(irreceiver_pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||||
|
|
||||||
|
# Counter
|
||||||
|
ctr = 0
|
||||||
|
value = GPIO.input(irreceiver_pin)
|
||||||
|
|
||||||
|
# mark time
|
||||||
|
startTime = datetime.now()
|
||||||
|
pulseTime = startTime
|
||||||
|
|
||||||
|
# Pulse Data
|
||||||
|
pulsedata = []
|
||||||
|
|
||||||
|
aborted = False
|
||||||
|
while aborted == False:
|
||||||
|
# Wait for transition
|
||||||
|
try:
|
||||||
|
if value:
|
||||||
|
channel = GPIO.wait_for_edge(irreceiver_pin, GPIO.FALLING, timeout=PULSETIMEOUTMS)
|
||||||
|
else:
|
||||||
|
channel = GPIO.wait_for_edge(irreceiver_pin, GPIO.RISING, timeout=PULSETIMEOUTMS)
|
||||||
|
except Exception as e:
|
||||||
|
# GPIO Error
|
||||||
|
GPIO.cleanup()
|
||||||
|
return [(-2, -2)]
|
||||||
|
|
||||||
|
if channel is None:
|
||||||
|
if ctr == 0:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
aborted = True
|
||||||
|
if len(pulsedata) == 0:
|
||||||
|
# CTRL+C
|
||||||
|
return [(-1, -1)]
|
||||||
|
break
|
||||||
|
|
||||||
|
# high/low Length
|
||||||
|
now = datetime.now()
|
||||||
|
pulseLength = now - pulseTime
|
||||||
|
pulseTime = now
|
||||||
|
|
||||||
|
# Update value (changed triggered), this also inverts value before saving
|
||||||
|
if value:
|
||||||
|
value = 0
|
||||||
|
else:
|
||||||
|
value = 1
|
||||||
|
if pulseLength.microseconds > PULSETAIL_MAXMICROS_NEC and ctr == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
pulsedata.append((value, pulseLength.microseconds))
|
||||||
|
|
||||||
|
ctr = ctr + 1
|
||||||
|
if pulseLength.microseconds > PULSETAIL_MAXMICROS_NEC:
|
||||||
|
break
|
||||||
|
elif ctr > PULSEDATA_MAXCOUNT:
|
||||||
|
break
|
||||||
|
|
||||||
|
GPIO.cleanup()
|
||||||
|
# Data is most likely incomplete
|
||||||
|
if aborted == True:
|
||||||
|
return []
|
||||||
|
elif ctr >= PULSEDATA_MAXCOUNT:
|
||||||
|
print (" * Unable to decode. Please try again *")
|
||||||
|
return []
|
||||||
|
return pulsedata
|
||||||
|
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# Use LIRC
|
||||||
|
def lircMode2Task(irlogfile):
|
||||||
|
os.system("mode2 > "+irlogfile+" 2>&1")
|
||||||
|
|
||||||
|
def startLIRCMode2Logging(irlogfile):
|
||||||
|
# create a new process
|
||||||
|
loggerprocess = Process(target=lircMode2Task,args=(irlogfile,))
|
||||||
|
loggerprocess.start()
|
||||||
|
# mode2 will start new process, terminate current
|
||||||
|
time.sleep(0.1)
|
||||||
|
loggerprocess.kill()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def endLIRCMode2Logging(irlogfile):
|
||||||
|
tmplogfile = irlogfile+".tmp"
|
||||||
|
os.system("ps | grep ode2 > "+tmplogfile+"")
|
||||||
|
|
||||||
|
if os.path.exists(tmplogfile) == True:
|
||||||
|
ctr = 0
|
||||||
|
fp = open(tmplogfile, "r")
|
||||||
|
for curline in fp:
|
||||||
|
if len(curline) > 0:
|
||||||
|
rowdata = curline.split(" ")
|
||||||
|
pid = ""
|
||||||
|
processname = ""
|
||||||
|
colidx = 0
|
||||||
|
while colidx < len(rowdata):
|
||||||
|
if len(rowdata[colidx]) > 0:
|
||||||
|
if pid == "":
|
||||||
|
pid = rowdata[colidx]
|
||||||
|
else:
|
||||||
|
processname = rowdata[colidx]
|
||||||
|
|
||||||
|
colidx = colidx + 1
|
||||||
|
if processname=="mode2\n":
|
||||||
|
os.system("kill -9 "+pid)
|
||||||
|
fp.close()
|
||||||
|
os.remove(tmplogfile)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def getLIRCPulseData():
|
||||||
|
if haslirclib == False:
|
||||||
|
print (" * LIRC Module not found, please reboot and try again *")
|
||||||
|
return []
|
||||||
|
|
||||||
|
irlogfile = "/dev/shm/lircdecoder.log"
|
||||||
|
|
||||||
|
loggerresult = startLIRCMode2Logging(irlogfile)
|
||||||
|
if loggerresult == False:
|
||||||
|
return [(-1, -1)]
|
||||||
|
|
||||||
|
# Wait for log file
|
||||||
|
logsize = 0
|
||||||
|
while logsize == 0:
|
||||||
|
if os.path.exists(irlogfile) == True:
|
||||||
|
logsize = os.path.getsize(irlogfile)
|
||||||
|
if logsize == 0:
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
# Wait for data to start
|
||||||
|
newlogsize = logsize
|
||||||
|
while logsize == newlogsize:
|
||||||
|
time.sleep(0.1)
|
||||||
|
newlogsize = os.path.getsize(irlogfile)
|
||||||
|
|
||||||
|
print(" Thank you")
|
||||||
|
|
||||||
|
# Wait for data to stop
|
||||||
|
while logsize != newlogsize:
|
||||||
|
logsize = newlogsize
|
||||||
|
time.sleep(0.1)
|
||||||
|
newlogsize = os.path.getsize(irlogfile)
|
||||||
|
|
||||||
|
# Finalize File
|
||||||
|
loggerresult = endLIRCMode2Logging(irlogfile)
|
||||||
|
if loggerresult == False:
|
||||||
|
return [(-1, -1)]
|
||||||
|
|
||||||
|
# Decode logfile into Pulse Data
|
||||||
|
pulsedata = []
|
||||||
|
|
||||||
|
terminated = False
|
||||||
|
if os.path.exists(irlogfile) == True:
|
||||||
|
ctr = 0
|
||||||
|
fp = open(irlogfile, "r")
|
||||||
|
for curline in fp:
|
||||||
|
if len(curline) > 0:
|
||||||
|
rowdata = curline.split(" ")
|
||||||
|
if len(rowdata) == 2:
|
||||||
|
duration = int(rowdata[1])
|
||||||
|
value = 0
|
||||||
|
if rowdata[0] == "pulse":
|
||||||
|
value = 1
|
||||||
|
ctr = ctr + 1
|
||||||
|
if value == 1 or ctr > 1:
|
||||||
|
if len(pulsedata) > 0 and duration > PULSELEADER_MINMICROS_NEC:
|
||||||
|
terminated = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
pulsedata.append((value, duration))
|
||||||
|
fp.close()
|
||||||
|
os.remove(irlogfile)
|
||||||
|
|
||||||
|
# Check if terminating pulse detected
|
||||||
|
if terminated == False:
|
||||||
|
print (" * Unable to read signal. Please try again *")
|
||||||
|
return []
|
||||||
|
return pulsedata
|
||||||
|
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# Common
|
||||||
|
irconffile = "/etc/lirc/lircd.conf.d/argon.lircd.conf"
|
||||||
|
|
||||||
|
# I2C
|
||||||
|
address = 0x1a # I2C Address
|
||||||
|
addressregister = 0xaa # I2C Address Register
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
PULSETIMEOUTMS = 1000
|
||||||
|
VERIFYTARGET = 3
|
||||||
|
PULSEDATA_MAXCOUNT = 200 # Fail safe
|
||||||
|
|
||||||
|
# NEC Protocol Constants
|
||||||
|
PULSEBIT_MAXMICROS_NEC = 2500
|
||||||
|
PULSEBIT_ZEROMICROS_NEC = 1000
|
||||||
|
|
||||||
|
PULSELEADER_MINMICROS_NEC = 8000
|
||||||
|
PULSELEADER_MAXMICROS_NEC = 10000
|
||||||
|
PULSETAIL_MAXMICROS_NEC = 12000
|
||||||
|
|
||||||
|
# Flags
|
||||||
|
FLAGV1ONLY = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.isfile("/etc/argon/flag_v1"):
|
||||||
|
FLAGV1ONLY = True
|
||||||
|
except Exception:
|
||||||
|
FLAGV1ONLY = False
|
||||||
|
|
||||||
|
# Standard Methods
|
||||||
|
def getbytestring(pulsedata):
|
||||||
|
outstring = ""
|
||||||
|
for curbyte in pulsedata:
|
||||||
|
tmpstr = hex(curbyte)[2:]
|
||||||
|
while len(tmpstr) < 2:
|
||||||
|
tmpstr = "0" + tmpstr
|
||||||
|
outstring = outstring+tmpstr
|
||||||
|
return outstring
|
||||||
|
|
||||||
|
def displaybyte(pulsedata):
|
||||||
|
print (getbytestring(pulsedata))
|
||||||
|
|
||||||
|
|
||||||
|
def pulse2byteNEC(pulsedata):
|
||||||
|
outdata = []
|
||||||
|
bitdata = 1
|
||||||
|
curbyte = 0
|
||||||
|
bitcount = 0
|
||||||
|
for (mode, duration) in pulsedata:
|
||||||
|
if mode == 1:
|
||||||
|
continue
|
||||||
|
elif duration > PULSEBIT_MAXMICROS_NEC:
|
||||||
|
continue
|
||||||
|
elif duration > PULSEBIT_ZEROMICROS_NEC:
|
||||||
|
curbyte = curbyte*2 + 1
|
||||||
|
else:
|
||||||
|
curbyte = curbyte*2
|
||||||
|
|
||||||
|
bitcount = bitcount + 1
|
||||||
|
if bitcount == 8:
|
||||||
|
outdata.append(curbyte)
|
||||||
|
curbyte = 0
|
||||||
|
bitcount = 0
|
||||||
|
# Shouldn't happen, but just in case
|
||||||
|
if bitcount > 0:
|
||||||
|
outdata.append(curbyte)
|
||||||
|
|
||||||
|
return outdata
|
||||||
|
|
||||||
|
|
||||||
|
def bytecompare(a, b):
|
||||||
|
idx = 0
|
||||||
|
maxidx = len(a)
|
||||||
|
if maxidx != len(b):
|
||||||
|
return 1
|
||||||
|
while idx < maxidx:
|
||||||
|
if a[idx] != b[idx]:
|
||||||
|
return 1
|
||||||
|
idx = idx + 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# Main Flow
|
||||||
|
mode = "custom"
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
mode = sys.argv[1]
|
||||||
|
|
||||||
|
powerdata = []
|
||||||
|
buttonlist = ['POWER', 'UP', 'DOWN', 'LEFT', 'RIGHT',
|
||||||
|
'VOLUMEUP', 'VOLUMEDOWN', 'OK', 'HOME', 'MENU'
|
||||||
|
'BACK']
|
||||||
|
|
||||||
|
ircodelist = ['00ff39c6', '00ff53ac', '00ff4bb4', '00ff9966', '00ff837c',
|
||||||
|
'00ff01fe', '00ff817e', '00ff738c', '00ffd32c', '00ffb946',
|
||||||
|
'00ff09f6']
|
||||||
|
|
||||||
|
buttonidx = 0
|
||||||
|
|
||||||
|
if mode == "power":
|
||||||
|
buttonlist = ['POWER']
|
||||||
|
ircodelist = ['']
|
||||||
|
elif mode == "resetpower":
|
||||||
|
# Just Set the power so it won't create/update the conf file
|
||||||
|
buttonlist = ['POWER']
|
||||||
|
mode = "default"
|
||||||
|
elif mode == "custom":
|
||||||
|
buttonlist = ['POWER', 'UP', 'DOWN', 'LEFT', 'RIGHT',
|
||||||
|
'VOLUMEUP', 'VOLUMEDOWN', 'OK', 'HOME', 'MENU'
|
||||||
|
'BACK']
|
||||||
|
ircodelist = ['', '', '', '', '',
|
||||||
|
'', '', '', '', '',
|
||||||
|
'']
|
||||||
|
#buttonlist = ['POWER', 'VOLUMEUP', 'VOLUMEDOWN']
|
||||||
|
#ircodelist = ['', '', '']
|
||||||
|
|
||||||
|
if mode == "default":
|
||||||
|
# To skip the decoding loop
|
||||||
|
buttonidx = len(buttonlist)
|
||||||
|
# Set MCU IR code
|
||||||
|
powerdata = [0x00, 0xff, 0x39, 0xc6]
|
||||||
|
else:
|
||||||
|
print ("************************************************")
|
||||||
|
print ("* WARNING: Current buttons are still active. *")
|
||||||
|
print ("* Please temporarily assign to a *")
|
||||||
|
print ("* different button if you plan to *")
|
||||||
|
print ("* reuse buttons. *")
|
||||||
|
print ("* e.g. Power Button triggers shutdown *")
|
||||||
|
print ("* *")
|
||||||
|
print ("* PROCEED AT YOUR OWN RISK *")
|
||||||
|
print ("* (Press CTRL+C to abort at any time) *")
|
||||||
|
print ("************************************************")
|
||||||
|
|
||||||
|
readaborted = False
|
||||||
|
# decoding loop
|
||||||
|
while buttonidx < len(buttonlist):
|
||||||
|
print ("Press your button for "+buttonlist[buttonidx]+" (CTRL+C to abort)")
|
||||||
|
irprotocol = ""
|
||||||
|
outdata = []
|
||||||
|
verifycount = 0
|
||||||
|
readongoing = True
|
||||||
|
|
||||||
|
# Handles NEC protocol Only
|
||||||
|
while readongoing == True:
|
||||||
|
# Try GPIO-based reading, if it fails, fallback to LIRC
|
||||||
|
pulsedata = getGPIOPulseData()
|
||||||
|
if len(pulsedata) == 1:
|
||||||
|
if pulsedata[0][0] == -2:
|
||||||
|
pulsedata = getLIRCPulseData()
|
||||||
|
|
||||||
|
# Aborted
|
||||||
|
if len(pulsedata) == 1:
|
||||||
|
if pulsedata[0][0] == -1:
|
||||||
|
readongoing = False
|
||||||
|
readaborted = True
|
||||||
|
buttonidx = len(buttonlist)
|
||||||
|
break
|
||||||
|
# Ignore repeat code (NEC)
|
||||||
|
if len(pulsedata) <= 4:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get leading signal
|
||||||
|
(mode, duration) = pulsedata[0]
|
||||||
|
|
||||||
|
# Decode IR Protocols
|
||||||
|
# https://www.sbprojects.net/knowledge/ir/index.php
|
||||||
|
|
||||||
|
if duration >= PULSELEADER_MINMICROS_NEC and duration <= PULSELEADER_MAXMICROS_NEC:
|
||||||
|
irprotocol = "NEC"
|
||||||
|
# NEC has 9ms head, +/- 1ms
|
||||||
|
curdata = pulse2byteNEC(pulsedata)
|
||||||
|
if len(curdata) > 0:
|
||||||
|
if verifycount > 0:
|
||||||
|
if bytecompare(outdata, curdata) == 0:
|
||||||
|
verifycount = verifycount + 1
|
||||||
|
else:
|
||||||
|
verifycount = 0
|
||||||
|
else:
|
||||||
|
outdata = curdata
|
||||||
|
verifycount = 1
|
||||||
|
|
||||||
|
if verifycount >= VERIFYTARGET:
|
||||||
|
readongoing = False
|
||||||
|
print ("")
|
||||||
|
elif verifycount == 0:
|
||||||
|
print (" * IR code mismatch, please try again *")
|
||||||
|
elif VERIFYTARGET - verifycount > 1:
|
||||||
|
print (" Press the button "+ str(VERIFYTARGET - verifycount)+ " more times")
|
||||||
|
else:
|
||||||
|
print (" Press the button 1 more time")
|
||||||
|
else:
|
||||||
|
print (" * Decoding error. Please try again *")
|
||||||
|
else:
|
||||||
|
print (" * Unrecognized signal. Please try again *")
|
||||||
|
#curdata = pulse2byteLSB(pulsedata)
|
||||||
|
#displaybyte(curdata)
|
||||||
|
|
||||||
|
# Check for duplicates
|
||||||
|
newircode = getbytestring(outdata)
|
||||||
|
if verifycount > 0:
|
||||||
|
checkidx = 0
|
||||||
|
while checkidx < buttonidx and checkidx < len(buttonlist):
|
||||||
|
if ircodelist[checkidx] == newircode:
|
||||||
|
print (" Button already assigned. Please try again")
|
||||||
|
verifycount = 0
|
||||||
|
break
|
||||||
|
checkidx = checkidx + 1
|
||||||
|
|
||||||
|
# Store code, and power button code if applicable
|
||||||
|
if verifycount > 0:
|
||||||
|
if buttonidx == 0:
|
||||||
|
powerdata = outdata
|
||||||
|
if buttonidx < len(buttonlist):
|
||||||
|
# Abort will cause out of bounds
|
||||||
|
ircodelist[buttonidx] = newircode
|
||||||
|
#print (buttonlist[buttonidx]+": "+ newircode)
|
||||||
|
buttonidx = buttonidx + 1
|
||||||
|
|
||||||
|
if len(powerdata) > 0 and readaborted == False:
|
||||||
|
# Send to device if completed or reset mode
|
||||||
|
#print("Writing " + getbytestring(powerdata))
|
||||||
|
print("Updating Device...")
|
||||||
|
try:
|
||||||
|
bus=smbus.SMBus(1)
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
# Older version
|
||||||
|
bus=smbus.SMBus(0)
|
||||||
|
except Exception:
|
||||||
|
bus=None
|
||||||
|
|
||||||
|
if bus is None:
|
||||||
|
print("Device Update Failed: Unable to detect i2c")
|
||||||
|
else:
|
||||||
|
# Check for Argon Control Register Support
|
||||||
|
checkircodewrite = False
|
||||||
|
argoncyclereg = 0x80
|
||||||
|
if FLAGV1ONLY == False:
|
||||||
|
oldval = bus.read_byte_data(address, argoncyclereg)
|
||||||
|
newval = oldval + 1
|
||||||
|
if newval >= 100:
|
||||||
|
newval = 98
|
||||||
|
bus.write_byte_data(address,argoncyclereg, newval)
|
||||||
|
time.sleep(1)
|
||||||
|
newval = bus.read_byte_data(address, argoncyclereg)
|
||||||
|
|
||||||
|
if newval != oldval:
|
||||||
|
addressregister = 0x82
|
||||||
|
checkircodewrite = True
|
||||||
|
bus.write_byte_data(address,argoncyclereg, oldval)
|
||||||
|
|
||||||
|
bus.write_i2c_block_data(address, addressregister, powerdata)
|
||||||
|
|
||||||
|
|
||||||
|
if checkircodewrite == True:
|
||||||
|
# Check if data was written for devices that support it
|
||||||
|
print("Verifying ...")
|
||||||
|
time.sleep(2)
|
||||||
|
checkircodedata = bus.read_i2c_block_data(address, addressregister, 4)
|
||||||
|
checkircodecounter = 0
|
||||||
|
while checkircodecounter < 4:
|
||||||
|
# Reuse readaborted flag as indicator if IR code was successfully updated
|
||||||
|
if checkircodedata[checkircodecounter] != powerdata[checkircodecounter]:
|
||||||
|
readaborted = True
|
||||||
|
checkircodecounter = checkircodecounter + 1
|
||||||
|
if readaborted == False:
|
||||||
|
print("Device Update Successful")
|
||||||
|
else:
|
||||||
|
print("Verification Failed")
|
||||||
|
bus.close()
|
||||||
|
|
||||||
|
# Update IR Conf if there are other button
|
||||||
|
if buttonidx > 1 and readaborted == False:
|
||||||
|
print("Updating Remote Control Codes...")
|
||||||
|
fp = open(irconffile, "w")
|
||||||
|
|
||||||
|
# Standard NEC conf header
|
||||||
|
fp.write("#\n")
|
||||||
|
fp.write("# Based on NEC templates at http://lirc.sourceforge.net/remotes/nec/\n")
|
||||||
|
fp.write("# Configured codes based on data gathered\n")
|
||||||
|
fp.write("#\n")
|
||||||
|
fp.write("\n")
|
||||||
|
fp.write("begin remote\n")
|
||||||
|
fp.write(" name argon\n")
|
||||||
|
fp.write(" bits 32\n")
|
||||||
|
fp.write(" flags SPACE_ENC\n")
|
||||||
|
fp.write(" eps 20\n")
|
||||||
|
fp.write(" aeps 200\n")
|
||||||
|
fp.write("\n")
|
||||||
|
fp.write(" header 8800 4400\n")
|
||||||
|
fp.write(" one 550 1650\n")
|
||||||
|
fp.write(" zero 550 550\n")
|
||||||
|
fp.write(" ptrail 550\n")
|
||||||
|
fp.write(" repeat 8800 2200\n")
|
||||||
|
fp.write(" gap 38500\n")
|
||||||
|
fp.write(" toggle_bit 0\n")
|
||||||
|
fp.write("\n")
|
||||||
|
fp.write(" frequency 38000\n")
|
||||||
|
fp.write("\n")
|
||||||
|
fp.write(" begin codes\n")
|
||||||
|
|
||||||
|
# Write Key Codes
|
||||||
|
buttonidx = 1
|
||||||
|
while buttonidx < len(buttonlist):
|
||||||
|
fp.write(" KEY_"+buttonlist[buttonidx]+" 0x"+ircodelist[buttonidx]+"\n")
|
||||||
|
buttonidx = buttonidx + 1
|
||||||
|
fp.write(" end codes\n")
|
||||||
|
fp.write("end remote\n")
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,471 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "*************"
|
||||||
|
echo " Argon Setup "
|
||||||
|
echo "*************"
|
||||||
|
|
||||||
|
|
||||||
|
# Check time if need to 'fix'
|
||||||
|
NEEDSTIMESYNC=0
|
||||||
|
LOCALTIME=$(date -u +%s%N | cut -b1-10)
|
||||||
|
GLOBALTIME=$(curl -s 'http://worldtimeapi.org/api/ip.txt' | grep unixtime | cut -b11-20)
|
||||||
|
TIMEDIFF=$((GLOBALTIME-LOCALTIME))
|
||||||
|
|
||||||
|
# about 26hrs, max timezone difference
|
||||||
|
if [ $TIMEDIFF -gt 100000 ]
|
||||||
|
then
|
||||||
|
NEEDSTIMESYNC=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
argon_time_error() {
|
||||||
|
echo "**********************************************"
|
||||||
|
echo "* WARNING: Device time seems to be incorrect *"
|
||||||
|
echo "* This may cause problems during setup. *"
|
||||||
|
echo "**********************************************"
|
||||||
|
echo "Possible Network Time Protocol Server issue"
|
||||||
|
echo "Try running the following to correct:"
|
||||||
|
echo " curl -k https://download.argon40.com/tools/setntpserver.sh | bash"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ $NEEDSTIMESYNC -eq 1 ]
|
||||||
|
then
|
||||||
|
argon_time_error
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Helper variables
|
||||||
|
ARGONDOWNLOADSERVER=https://download.argon40.com
|
||||||
|
|
||||||
|
INSTALLATIONFOLDER=/etc/argon
|
||||||
|
pythonbin="sudo /usr/bin/python3"
|
||||||
|
|
||||||
|
versioninfoscript=$INSTALLATIONFOLDER/argon-versioninfo.sh
|
||||||
|
|
||||||
|
uninstallscript=$INSTALLATIONFOLDER/argon-uninstall.sh
|
||||||
|
configscript=$INSTALLATIONFOLDER/argon-config
|
||||||
|
argondashboardscript=$INSTALLATIONFOLDER/argondashboard.py
|
||||||
|
|
||||||
|
|
||||||
|
setupmode="Setup"
|
||||||
|
|
||||||
|
if [ -f $configscript ]
|
||||||
|
then
|
||||||
|
setupmode="Update"
|
||||||
|
echo "Updating files"
|
||||||
|
else
|
||||||
|
sudo mkdir $INSTALLATIONFOLDER
|
||||||
|
sudo chmod 755 $INSTALLATIONFOLDER
|
||||||
|
fi
|
||||||
|
|
||||||
|
##########
|
||||||
|
# Start code lifted from raspi-config
|
||||||
|
# set_config_var based on raspi-config
|
||||||
|
|
||||||
|
if [ -e /boot/firmware/config.txt ] ; then
|
||||||
|
FIRMWARE=/firmware
|
||||||
|
else
|
||||||
|
FIRMWARE=
|
||||||
|
fi
|
||||||
|
CONFIG=/boot${FIRMWARE}/config.txt
|
||||||
|
|
||||||
|
set_config_var() {
|
||||||
|
if ! grep -q -E "$1=$2" $3 ; then
|
||||||
|
echo "$1=$2" | sudo tee -a $3 > /dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# End code lifted from raspi-config
|
||||||
|
##########
|
||||||
|
|
||||||
|
# Reuse set_config_var
|
||||||
|
set_nvme_default() {
|
||||||
|
set_config_var dtparam nvme $CONFIG
|
||||||
|
set_config_var dtparam=pciex1_gen 3 $CONFIG
|
||||||
|
}
|
||||||
|
|
||||||
|
set_external_antenna() {
|
||||||
|
set_config_var dtparam ant2 $CONFIG
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
argon_check_pkg() {
|
||||||
|
RESULT=$(dpkg-query -W -f='${Status}\n' "$1" 2> /dev/null | grep "installed")
|
||||||
|
|
||||||
|
if [ "" == "$RESULT" ]; then
|
||||||
|
echo "NG"
|
||||||
|
else
|
||||||
|
echo "OK"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CHECKDEVICE="oneup" # Hardcoded for argononeup
|
||||||
|
|
||||||
|
CHECKGPIOMODE="libgpiod" # libgpiod 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
|
||||||
|
|
||||||
|
gpiopkg="python3-libgpiod"
|
||||||
|
if [ "$CHECKGPIOMODE" = "rpigpio" ]
|
||||||
|
then
|
||||||
|
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
||||||
|
then
|
||||||
|
gpiopkg="raspi-gpio python3-rpi.gpio"
|
||||||
|
else
|
||||||
|
gpiopkg="python3-rpi.gpio"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
pkglist=($gpiopkg python3-smbus i2c-tools python3-evdev ddcutil)
|
||||||
|
|
||||||
|
echo "Installing/updating dependencies..."
|
||||||
|
|
||||||
|
for curpkg in ${pkglist[@]}; do
|
||||||
|
sudo apt-get install -y $curpkg
|
||||||
|
RESULT=$(argon_check_pkg "$curpkg")
|
||||||
|
if [ "NG" == "$RESULT" ]
|
||||||
|
then
|
||||||
|
echo "********************************************************************"
|
||||||
|
echo "Please also connect device to the internet and restart installation."
|
||||||
|
echo "********************************************************************"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Updating configuration ..."
|
||||||
|
|
||||||
|
# Ubuntu Mate for RPi has raspi-config too
|
||||||
|
command -v raspi-config &> /dev/null
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
# Enable i2c
|
||||||
|
sudo raspi-config nonint do_i2c 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Added to enabled NVMe for pi5
|
||||||
|
set_nvme_default
|
||||||
|
|
||||||
|
# Fan Setup
|
||||||
|
basename="argononeup"
|
||||||
|
daemonname=$basename"d"
|
||||||
|
eepromrpiscript="/usr/bin/rpi-eeprom-config"
|
||||||
|
eepromconfigscript=$INSTALLATIONFOLDER/${basename}-eepromconfig.py
|
||||||
|
daemonscript=$INSTALLATIONFOLDER/$daemonname.py
|
||||||
|
daemonservice=/lib/systemd/system/$daemonname.service
|
||||||
|
userdaemonservice=/etc/systemd/user/${daemonname}user.service
|
||||||
|
daemonconfigfile=/etc/$daemonname.conf
|
||||||
|
|
||||||
|
lidconfigscript=$INSTALLATIONFOLDER/${basename}-lidconfig.sh
|
||||||
|
|
||||||
|
|
||||||
|
for TMPDIRECTORY in "/lib/systemd/system"
|
||||||
|
do
|
||||||
|
sudo mkdir -p "$TMPDIRECTORY"
|
||||||
|
sudo chmod 755 $TMPDIRECTORY
|
||||||
|
sudo chown root:root "$TMPDIRECTORY"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Installing/Updating scripts and services ..."
|
||||||
|
|
||||||
|
if [ ! -f $daemonconfigfile ]; then
|
||||||
|
# Generate config file for fan speed
|
||||||
|
sudo touch $daemonconfigfile
|
||||||
|
sudo chmod 666 $daemonconfigfile
|
||||||
|
echo '#' >> $daemonconfigfile
|
||||||
|
echo '# Argon One Up Configuration' >> $daemonconfigfile
|
||||||
|
echo '#' >> $daemonconfigfile
|
||||||
|
echo '# lidshutdownsecs number of seconds till shutdown when lid is closed 0 if do nothing' >> $daemonconfigfile
|
||||||
|
echo 'lidshutdownsecs=300' >> $daemonconfigfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Lid Config Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argononeup-lidconfig.sh -O $lidconfigscript --quiet
|
||||||
|
sudo chmod 755 $lidconfigscript
|
||||||
|
|
||||||
|
|
||||||
|
if [ -f "$eepromrpiscript" ]
|
||||||
|
then
|
||||||
|
# EEPROM Config Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-rpi-eeprom-config-psu.py -O $eepromconfigscript --quiet
|
||||||
|
sudo chmod 755 $eepromconfigscript
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Daemon/Service Files
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/${daemonname}.py -O $daemonscript --quiet
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/${daemonname}.service -O $daemonservice --quiet
|
||||||
|
sudo chmod 644 $daemonservice
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/${daemonname}user.service -O $userdaemonservice --quiet
|
||||||
|
sudo chmod 644 $userdaemonservice
|
||||||
|
|
||||||
|
|
||||||
|
# Battery Images
|
||||||
|
if [ ! -d "$INSTALLATIONFOLDER/ups" ]
|
||||||
|
then
|
||||||
|
sudo mkdir $INSTALLATIONFOLDER/ups
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
|
||||||
|
sudo wget "$ARGONDOWNLOADSERVER/scripts/argonpowerbutton-${CHECKGPIOMODE}.py" -O $INSTALLATIONFOLDER/argonpowerbutton.py --quiet
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonkeyboard.py -O $INSTALLATIONFOLDER/argonkeyboard.py --quiet
|
||||||
|
|
||||||
|
# Other utility scripts
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argondashboard.py -O $INSTALLATIONFOLDER/argondashboard.py --quiet
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-versioninfo.sh -O $versioninfoscript --quiet
|
||||||
|
sudo chmod 755 $versioninfoscript
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonsysinfo.py -O $INSTALLATIONFOLDER/argonsysinfo.py --quiet
|
||||||
|
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argonregister-v1.py -O $INSTALLATIONFOLDER/argonregister.py --quiet
|
||||||
|
|
||||||
|
|
||||||
|
# Argon Uninstall Script
|
||||||
|
sudo wget $ARGONDOWNLOADSERVER/scripts/argon-uninstall.sh -O $uninstallscript --quiet
|
||||||
|
sudo chmod 755 $uninstallscript
|
||||||
|
|
||||||
|
# Argon Config Script
|
||||||
|
if [ -f $configscript ]; then
|
||||||
|
sudo rm $configscript
|
||||||
|
fi
|
||||||
|
sudo touch $configscript
|
||||||
|
|
||||||
|
# To ensure we can write the following lines
|
||||||
|
sudo chmod 666 $configscript
|
||||||
|
|
||||||
|
echo '#!/bin/bash' >> $configscript
|
||||||
|
|
||||||
|
echo 'echo "--------------------------"' >> $configscript
|
||||||
|
echo 'echo "Argon Configuration Tool"' >> $configscript
|
||||||
|
echo "$versioninfoscript simple" >> $configscript
|
||||||
|
echo 'echo "--------------------------"' >> $configscript
|
||||||
|
|
||||||
|
echo 'get_number () {' >> $configscript
|
||||||
|
echo ' read curnumber' >> $configscript
|
||||||
|
echo ' if [ -z "$curnumber" ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' echo "-2"' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo ' elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' if [ $curnumber -lt 0 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' echo "-1"' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo ' elif [ $curnumber -gt 100 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' echo "-1"' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo ' fi ' >> $configscript
|
||||||
|
echo ' echo $curnumber' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo ' fi' >> $configscript
|
||||||
|
echo ' echo "-1"' >> $configscript
|
||||||
|
echo ' return' >> $configscript
|
||||||
|
echo '}' >> $configscript
|
||||||
|
echo '' >> $configscript
|
||||||
|
|
||||||
|
echo 'mainloopflag=1' >> $configscript
|
||||||
|
echo 'while [ $mainloopflag -eq 1 ]' >> $configscript
|
||||||
|
echo 'do' >> $configscript
|
||||||
|
echo ' echo' >> $configscript
|
||||||
|
echo ' echo "Choose Option:"' >> $configscript
|
||||||
|
|
||||||
|
|
||||||
|
echo ' echo " 1. Get Battery Status"' >> $configscript
|
||||||
|
echo ' echo " 2. Configure Lid Behavior"' >> $configscript
|
||||||
|
|
||||||
|
|
||||||
|
uninstalloption="4"
|
||||||
|
|
||||||
|
statusoption=$(($uninstalloption-1))
|
||||||
|
echo " echo \" $statusoption. Dashboard\"" >> $configscript
|
||||||
|
|
||||||
|
echo " echo \" $uninstalloption. Uninstall\"" >> $configscript
|
||||||
|
echo ' echo ""' >> $configscript
|
||||||
|
echo ' echo " 0. Exit"' >> $configscript
|
||||||
|
echo " echo -n \"Enter Number (0-$uninstalloption):\"" >> $configscript
|
||||||
|
echo ' newmode=$( get_number )' >> $configscript
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
echo ' if [ $newmode -eq 0 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo ' echo "Thank you."' >> $configscript
|
||||||
|
echo ' mainloopflag=0' >> $configscript
|
||||||
|
echo ' elif [ $newmode -eq 1 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
|
||||||
|
# Option 1
|
||||||
|
echo " $pythonbin $daemonscript GETBATTERY" >> $configscript
|
||||||
|
|
||||||
|
echo ' elif [ $newmode -eq 2 ]' >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
|
||||||
|
# Option 2
|
||||||
|
echo " $lidconfigscript" >> $configscript
|
||||||
|
|
||||||
|
# Standard options
|
||||||
|
echo " elif [ \$newmode -eq $statusoption ]" >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $pythonbin $argondashboardscript" >> $configscript
|
||||||
|
|
||||||
|
echo " elif [ \$newmode -eq $uninstalloption ]" >> $configscript
|
||||||
|
echo ' then' >> $configscript
|
||||||
|
echo " $uninstallscript" >> $configscript
|
||||||
|
echo ' mainloopflag=0' >> $configscript
|
||||||
|
echo ' fi' >> $configscript
|
||||||
|
echo 'done' >> $configscript
|
||||||
|
|
||||||
|
sudo chmod 755 $configscript
|
||||||
|
|
||||||
|
# Desktop Icon
|
||||||
|
destfoldername=$USERNAME
|
||||||
|
if [ -z "$destfoldername" ]
|
||||||
|
then
|
||||||
|
destfoldername=$USER
|
||||||
|
fi
|
||||||
|
if [ -z "$destfoldername" ]
|
||||||
|
then
|
||||||
|
destfoldername="pi"
|
||||||
|
fi
|
||||||
|
|
||||||
|
shortcutfile="/home/$destfoldername/Desktop/argononeup.desktop"
|
||||||
|
if [ -d "/home/$destfoldername/Desktop" ]
|
||||||
|
then
|
||||||
|
echo "Creating/Updating Desktop Elements ..."
|
||||||
|
|
||||||
|
terminalcmd="lxterminal --working-directory=/home/$destfoldername/ -t"
|
||||||
|
if [ -f "/home/$destfoldername/.twisteros.twid" ]
|
||||||
|
then
|
||||||
|
terminalcmd="xfce4-terminal --default-working-directory=/home/$destfoldername/ -T"
|
||||||
|
fi
|
||||||
|
imagefile=argon40.png
|
||||||
|
sudo wget https://download.argon40.com/$imagefile -O /etc/argon/$imagefile --quiet
|
||||||
|
if [ -f $shortcutfile ]; then
|
||||||
|
sudo rm $shortcutfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create Shortcuts
|
||||||
|
echo "[Desktop Entry]" > $shortcutfile
|
||||||
|
echo "Name=Argon Configuration" >> $shortcutfile
|
||||||
|
echo "Comment=Argon Configuration" >> $shortcutfile
|
||||||
|
echo "Icon=/etc/argon/$imagefile" >> $shortcutfile
|
||||||
|
echo 'Exec='$terminalcmd' "Argon Configuration" -e '$configscript >> $shortcutfile
|
||||||
|
echo "Type=Application" >> $shortcutfile
|
||||||
|
echo "Encoding=UTF-8" >> $shortcutfile
|
||||||
|
echo "Terminal=false" >> $shortcutfile
|
||||||
|
echo "Categories=None;" >> $shortcutfile
|
||||||
|
chmod 755 $shortcutfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
configcmd="$(basename -- $configscript)"
|
||||||
|
|
||||||
|
echo "Initializing Services ..."
|
||||||
|
|
||||||
|
# Force remove lock files
|
||||||
|
sudo rm -f /dev/shm/argononeupkeyboardlock.txt
|
||||||
|
sudo rm -f /dev/shm/argononeupkeyboardlock.txt.a
|
||||||
|
|
||||||
|
if [ "$setupmode" = "Setup" ]
|
||||||
|
then
|
||||||
|
if [ -f "/usr/bin/$configcmd" ]
|
||||||
|
then
|
||||||
|
sudo rm /usr/bin/$configcmd
|
||||||
|
fi
|
||||||
|
sudo ln -s $configscript /usr/bin/$configcmd
|
||||||
|
|
||||||
|
# Enable and Start Service(s)
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable argononeupd.service
|
||||||
|
sudo systemctl start argononeupd.service
|
||||||
|
else
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl restart argononeupd.service
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable and Start User Service(s)
|
||||||
|
for tmpuser in `awk -F: '{ if ($3 >= 1000) print $1 }' /etc/passwd`
|
||||||
|
do
|
||||||
|
if [ "$tmpuser" != "nobody" ]
|
||||||
|
then
|
||||||
|
if [ "$setupmode" = "Setup" ]
|
||||||
|
then
|
||||||
|
sudo -u "$tmpuser" systemctl --user enable argononeupduser.service
|
||||||
|
sudo -u "$tmpuser" systemctl --user start argononeupduser.service
|
||||||
|
else
|
||||||
|
sudo -u "$tmpuser" systemctl --user restart argononeupduser.service
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Current user / fallback
|
||||||
|
if [ "$setupmode" = "Setup" ]
|
||||||
|
then
|
||||||
|
systemctl --user enable argononeupduser.service
|
||||||
|
systemctl --user start argononeupduser.service
|
||||||
|
else
|
||||||
|
systemctl --user restart argononeupduser.service
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$CHECKPLATFORM" = "Raspbian" ]
|
||||||
|
then
|
||||||
|
if [ -f "$eepromrpiscript" ]
|
||||||
|
then
|
||||||
|
echo "Checking EEPROM ..."
|
||||||
|
sudo apt-get update && sudo apt-get upgrade -y
|
||||||
|
sudo rpi-eeprom-update
|
||||||
|
# EEPROM Config Script
|
||||||
|
sudo $eepromconfigscript
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "WARNING: EEPROM not updated. Please run this under Raspberry Pi OS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
echo "*********************"
|
||||||
|
echo " $setupmode Completed "
|
||||||
|
echo "*********************"
|
||||||
|
$versioninfoscript
|
||||||
|
echo
|
||||||
|
echo "Use '$configcmd' to configure device"
|
||||||
|
echo
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if [ $NEEDSTIMESYNC -eq 1 ]
|
||||||
|
then
|
||||||
|
argon_time_error
|
||||||
|
fi
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -0,0 +1,576 @@
|
|||||||
|
#!/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 NVMe boot priority etc if not yet set
|
||||||
|
foundnewsetting = 0
|
||||||
|
addsetting="\nBOOT_UART=1\nWAKE_ON_GPIO=0\nPOWER_OFF_ON_HALT=1\nBOOT_ORDER=0xf416\nPCIE_PROBE=1"
|
||||||
|
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] == "BOOT_UART":
|
||||||
|
newsetting = "BOOT_UART=1"
|
||||||
|
elif current_config_pair[0] == "WAKE_ON_GPIO":
|
||||||
|
newsetting = "WAKE_ON_GPIO=0"
|
||||||
|
elif current_config_pair[0] == "POWER_OFF_ON_HALT":
|
||||||
|
newsetting = "POWER_OFF_ON_HALT=1"
|
||||||
|
elif current_config_pair[0] == "BOOT_ORDER":
|
||||||
|
newsetting = "BOOT_ORDER=0xf416"
|
||||||
|
elif current_config_pair[0] == "PCIE_PROBE":
|
||||||
|
newsetting = "PCIE_PROBE=1"
|
||||||
|
|
||||||
|
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()
|
||||||
@@ -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()
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#!/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
|
||||||
|
if [ -f "$argononefanscript" ]
|
||||||
|
then
|
||||||
|
$pythonbin $argononefanscript FANOFF
|
||||||
|
fi
|
||||||
|
if [ "$1" = "poweroff" ] || [ "$1" = "halt" ]
|
||||||
|
then
|
||||||
|
if [ -f $argonirconfigscript ]
|
||||||
|
then
|
||||||
|
if [ -f $argoneonrtcscript ]
|
||||||
|
then
|
||||||
|
$pythonbin $argoneonrtcscript SHUTDOWN
|
||||||
|
fi
|
||||||
|
$pythonbin $argononefanscript SHUTDOWN
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
#!/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
|
||||||
|
shortcutfile="/home/$destfoldername/Desktop/argononeup.desktop"
|
||||||
|
if [ -f "$shortcutfile" ]; then
|
||||||
|
sudo rm $shortcutfile
|
||||||
|
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
|
||||||
|
|
||||||
|
argononeupscript=$INSTALLATIONFOLDER/argononeupd.py
|
||||||
|
if [ -f $argononeupscript ]; then
|
||||||
|
sudo systemctl stop argononeupd.service
|
||||||
|
sudo systemctl disable argononeupd.service
|
||||||
|
|
||||||
|
# Remove files
|
||||||
|
sudo rm /lib/systemd/system/argononeupd.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
|
||||||
|
|
||||||
|
|
||||||
|
# Remove UPS daemon if any
|
||||||
|
argononeupsscript=$INSTALLATIONFOLDER/argononeupd.py
|
||||||
|
if [ -f "$argononeupsscript" ]
|
||||||
|
then
|
||||||
|
#sudo rmmod argonbatteryicon
|
||||||
|
# Disable Services
|
||||||
|
sudo systemctl stop argononeupd.service
|
||||||
|
sudo systemctl disable argononeupd.service
|
||||||
|
|
||||||
|
for tmpuser in `awk -F: '{ if ($3 >= 1000) print $1 }' /etc/passwd`
|
||||||
|
do
|
||||||
|
if [ "$tmpuser" != "nobody" ]
|
||||||
|
then
|
||||||
|
sudo -u "$tmpuser" systemctl --user stop argononeupduser.service
|
||||||
|
sudo -u "$tmpuser" systemctl --user disable argononeupduser.service
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
systemctl --user stop argononeupduser.service
|
||||||
|
systemctl --user disable argononeupduser.service
|
||||||
|
|
||||||
|
# Remove files
|
||||||
|
sudo rm /lib/systemd/system/argononeupd.service
|
||||||
|
sudo rm /etc/systemd/user/argononeupduser.service
|
||||||
|
|
||||||
|
find "/home" -maxdepth 1 -type d | while read line; do
|
||||||
|
shortcutfile="$line/Desktop/argononeup.desktop"
|
||||||
|
if [ -f "$shortcutfile" ]; then
|
||||||
|
sudo rm $shortcutfile
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [ -f "/usr/bin/argon-config" ]
|
||||||
|
then
|
||||||
|
sudo rm /usr/bin/argon-config
|
||||||
|
fi
|
||||||
|
|
||||||
|
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 argononeupd
|
||||||
|
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."
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
VERSIONINFO="2603002"
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
#!/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
|
||||||
|
|
||||||
|
try:
|
||||||
|
curses.wrapper(mainloop)
|
||||||
|
except Exception as wrapperr:
|
||||||
|
pass
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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()
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,824 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
#
|
||||||
|
# This script monitor battery via ic2 and keyboard events.
|
||||||
|
#
|
||||||
|
# Additional comments are found in each function below
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
from evdev import InputDevice, categorize, ecodes, list_devices
|
||||||
|
from select import select
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
from threading import Thread
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
|
||||||
|
UPS_LOGFILE="/dev/shm/upslog.txt"
|
||||||
|
KEYBOARD_LOCKFILE="/dev/shm/argononeupkeyboardlock.txt"
|
||||||
|
|
||||||
|
|
||||||
|
KEYCODE_BRIGHTNESSUP = "KEY_BRIGHTNESSUP"
|
||||||
|
KEYCODE_BRIGHTNESSDOWN = "KEY_BRIGHTNESSDOWN"
|
||||||
|
KEYCODE_VOLUMEUP = "KEY_VOLUMEUP"
|
||||||
|
KEYCODE_VOLUMEDOWN = "KEY_VOLUMEDOWN"
|
||||||
|
KEYCODE_PAUSE = "KEY_PAUSE"
|
||||||
|
KEYCODE_MUTE = "KEY_MUTE"
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Utilty Functions
|
||||||
|
###################
|
||||||
|
|
||||||
|
# Debug Logger
|
||||||
|
def debuglog(typestr, logstr):
|
||||||
|
return
|
||||||
|
# try:
|
||||||
|
# DEBUGFILE="/dev/shm/argononeupkeyboarddebuglog.txt"
|
||||||
|
# tmpstrpadding = " "
|
||||||
|
|
||||||
|
# with open(DEBUGFILE, "a") as txt_file:
|
||||||
|
# txt_file.write("["+time.asctime(time.localtime(time.time()))+"] "+typestr.upper()+" "+logstr.strip().replace("\n","\n"+tmpstrpadding)+"\n")
|
||||||
|
# except:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
def runcmdlist(key, cmdlist):
|
||||||
|
try:
|
||||||
|
cmdresult = subprocess.run(cmdlist,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
check=True
|
||||||
|
)
|
||||||
|
#debuglog(key+"-result-output",str(cmdresult.stdout))
|
||||||
|
if cmdresult.stderr:
|
||||||
|
debuglog(key+"-result-error",str(cmdresult.stderr))
|
||||||
|
#debuglog(key+"-result-code",str(cmdresult.returncode))
|
||||||
|
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
debuglog(key+"-error-output",str(e.stdout))
|
||||||
|
if e.stderr:
|
||||||
|
debuglog(key+"-error-error",str(e.stderr))
|
||||||
|
debuglog(key+"-error-code",str(e.returncode))
|
||||||
|
except FileNotFoundError:
|
||||||
|
debuglog(key+"-error-filenotfound","Command Not Found")
|
||||||
|
except Exception as othererr:
|
||||||
|
try:
|
||||||
|
debuglog(key+"-error-other", str(othererr))
|
||||||
|
except:
|
||||||
|
debuglog(key+"-error-other", "Other Error")
|
||||||
|
|
||||||
|
def createlockfile(fname):
|
||||||
|
# try:
|
||||||
|
# if os.path.isfile(fname):
|
||||||
|
# return True
|
||||||
|
# except Exception as checklockerror:
|
||||||
|
# try:
|
||||||
|
# debuglog("keyboard-lock-error", str(checklockerror))
|
||||||
|
# except:
|
||||||
|
# debuglog("keyboard-lock-error", "Error Checking Lock File")
|
||||||
|
# try:
|
||||||
|
# with open(fname, "w") as txt_file:
|
||||||
|
# txt_file.write(time.asctime(time.localtime(time.time()))+"\n")
|
||||||
|
# except Exception as lockerror:
|
||||||
|
# try:
|
||||||
|
# debuglog("keyboard-lock-error", str(lockerror))
|
||||||
|
# except:
|
||||||
|
# debuglog("keyboard-lock-error", "Error Creating Lock File")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def deletelockfile(fname):
|
||||||
|
# try:
|
||||||
|
# os.remove(fname)
|
||||||
|
# except Exception as lockerror:
|
||||||
|
# try:
|
||||||
|
# debuglog("keyboard-lock-error", str(lockerror))
|
||||||
|
# except:
|
||||||
|
# debuglog("keyboard-lock-error", "Error Removing Lock File")
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# System Notifcation
|
||||||
|
def notifymessage(message, iscritical):
|
||||||
|
if not isinstance(message, str) or len(message.strip()) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
wftype="notify"
|
||||||
|
if iscritical:
|
||||||
|
wftype="critical"
|
||||||
|
os.system("export SUDO_UID=1000; wfpanelctl "+wftype+" \""+message+"\"")
|
||||||
|
os.system("export DISPLAY=:0.0; lxpanelctl notify \""+message+"\"")
|
||||||
|
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Battery (copied)
|
||||||
|
#############
|
||||||
|
|
||||||
|
def battery_loadlogdata():
|
||||||
|
# status, version, time, schedule
|
||||||
|
outobj = {}
|
||||||
|
try:
|
||||||
|
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
|
||||||
|
except Exception as einit:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-battery-error", str(einit))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-battery-error", "Error getting battery status")
|
||||||
|
#pass
|
||||||
|
|
||||||
|
return outobj
|
||||||
|
|
||||||
|
|
||||||
|
def keyboardevent_getdevicepaths():
|
||||||
|
outlist = []
|
||||||
|
try:
|
||||||
|
for path in list_devices():
|
||||||
|
try:
|
||||||
|
tmpdevice = InputDevice(path)
|
||||||
|
keyeventlist = tmpdevice.capabilities().get(ecodes.EV_KEY, [])
|
||||||
|
# Keyboard has EV_KEY (key) and EV_REP (autorepeat)
|
||||||
|
if ecodes.KEY_BRIGHTNESSDOWN in keyeventlist and ecodes.KEY_BRIGHTNESSDOWN in keyeventlist:
|
||||||
|
outlist.append(path)
|
||||||
|
#debuglog("keyboard-device-keys", path)
|
||||||
|
#debuglog("keyboard-device-keys", str(keyeventlist))
|
||||||
|
elif ecodes.KEY_F2 in keyeventlist and ecodes.KEY_F3 in keyeventlist:
|
||||||
|
# Keyboards with FN key sometimes do not include KEY_BRIGHTNESS in declaration
|
||||||
|
outlist.append(path)
|
||||||
|
#debuglog("keyboard-device-keys", path)
|
||||||
|
#debuglog("keyboard-device-keys", str(keyeventlist))
|
||||||
|
tmpdevice.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return outlist
|
||||||
|
|
||||||
|
def keyboardevent_devicechanged(curlist, newlist):
|
||||||
|
try:
|
||||||
|
for curpath in curlist:
|
||||||
|
if curpath not in newlist:
|
||||||
|
return True
|
||||||
|
for newpath in newlist:
|
||||||
|
if newpath not in curlist:
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
def keyboardevent_getbrigthnesstoolid():
|
||||||
|
toolid = 0
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(["ddcutil", "--version"], text=True, stderr=subprocess.DEVNULL)
|
||||||
|
lines = output.splitlines()
|
||||||
|
if len(lines) > 0:
|
||||||
|
tmpline = lines[0].strip()
|
||||||
|
toolid = int(tmpline.split(" ")[1].split(".")[0])
|
||||||
|
except Exception as einit:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-brightness-tool-error", str(einit))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-brightness-tool-error", "Error getting tool id value")
|
||||||
|
|
||||||
|
debuglog("keyboard-brightness-tool", toolid)
|
||||||
|
return toolid
|
||||||
|
|
||||||
|
def keyboardevent_getbrigthnessinfo(toolid, defaultlevel=50):
|
||||||
|
level = defaultlevel
|
||||||
|
try:
|
||||||
|
# VCP code x10(Brightness ): current value = 90, max value = 100
|
||||||
|
if toolid > 1:
|
||||||
|
# Disabled dynamic sleep "--disable-dynamic-sleep", "--sleep-multiplier", "0.1"
|
||||||
|
output = subprocess.check_output(["ddcutil", "--skip-ddc-checks", "--disable-dynamic-sleep", "--sleep-multiplier", "0.1", "getvcp", "10"], text=True, stderr=subprocess.DEVNULL)
|
||||||
|
else:
|
||||||
|
output = subprocess.check_output(["ddcutil", "--sleep-multiplier", "0.1", "getvcp", "10"], text=True, stderr=subprocess.DEVNULL)
|
||||||
|
debuglog("keyboard-brightness-info", output)
|
||||||
|
level = int(output.split(":")[-1].split(",")[0].split("=")[-1].strip())
|
||||||
|
except Exception as einit:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-brightness-error", str(einit))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-brightness-error", "Error getting base value")
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
"level": level
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def keyboardevent_adjustbrigthness(toolid, baselevel, adjustval=5):
|
||||||
|
curlevel = baselevel
|
||||||
|
if adjustval == 0:
|
||||||
|
return {
|
||||||
|
"level": baselevel
|
||||||
|
}
|
||||||
|
|
||||||
|
# Moved reading because ddcutil has delay
|
||||||
|
# try:
|
||||||
|
# tmpobj = keyboardevent_getbrigthnessinfo(toolid, curlevel)
|
||||||
|
# curlevel = tmpobj["level"]
|
||||||
|
# except Exception:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
tmpval = max(10, min(100, curlevel + adjustval))
|
||||||
|
if tmpval != curlevel:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-brightness", str(curlevel)+"% to "+str(tmpval)+"%")
|
||||||
|
if toolid > 1:
|
||||||
|
# Disabled dynamic sleep "--disable-dynamic-sleep", "--sleep-multiplier", "0.1"
|
||||||
|
runcmdlist("brightness", ["ddcutil", "--skip-ddc-checks", "--disable-dynamic-sleep", "--sleep-multiplier", "0.1", "setvcp", "10", str(tmpval)])
|
||||||
|
else:
|
||||||
|
runcmdlist("brightness", ["ddcutil", "--sleep-multiplier", "0.1", "setvcp", "10", str(tmpval)])
|
||||||
|
notifymessage("Brightness: "+str(tmpval)+"%", False)
|
||||||
|
except Exception as adjusterr:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-brightness-error", str(adjusterr))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-brightness-error", "Error adjusting value")
|
||||||
|
return {
|
||||||
|
"level": curlevel
|
||||||
|
}
|
||||||
|
|
||||||
|
# DEBUG: Checking
|
||||||
|
#keyboardevent_getbrigthnessinfo(toolid, tmpval)
|
||||||
|
return {
|
||||||
|
"level": tmpval
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def keyboardevent_getvolumesinkid(usedefault=True):
|
||||||
|
if usedefault == True:
|
||||||
|
return "@DEFAULT_SINK@"
|
||||||
|
cursinkid = 0
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(["wpctl", "status"], text=True, encoding='utf-8', stderr=subprocess.DEVNULL)
|
||||||
|
|
||||||
|
# Find Audio section
|
||||||
|
tmpline = ""
|
||||||
|
foundidx = 0
|
||||||
|
lines = output.splitlines()
|
||||||
|
lineidx = 0
|
||||||
|
while lineidx < len(lines):
|
||||||
|
tmpline = lines[lineidx].strip()
|
||||||
|
if tmpline == "Audio":
|
||||||
|
foundidx = lineidx
|
||||||
|
break
|
||||||
|
lineidx = lineidx + 1
|
||||||
|
|
||||||
|
if foundidx < 1:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Find Sinks section
|
||||||
|
foundidx = 0
|
||||||
|
lineidx = lineidx + 1
|
||||||
|
while lineidx < len(lines):
|
||||||
|
if "Sinks:" in lines[lineidx]:
|
||||||
|
foundidx = lineidx
|
||||||
|
break
|
||||||
|
elif len(lines[lineidx]) < 1:
|
||||||
|
break
|
||||||
|
lineidx = lineidx + 1
|
||||||
|
|
||||||
|
if foundidx < 1:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Get find default id, or first id
|
||||||
|
lineidx = lineidx + 1
|
||||||
|
while lineidx < len(lines):
|
||||||
|
if "vol:" in lines[lineidx] and "." in lines[lineidx]:
|
||||||
|
tmpstr = lines[lineidx].split(".")[0]
|
||||||
|
tmplist = tmpstr.split()
|
||||||
|
if len(tmplist) > 1:
|
||||||
|
if tmplist[len(tmplist)-2] == "*":
|
||||||
|
return int(tmplist[len(tmplist)-1])
|
||||||
|
if len(tmplist) > 0 and cursinkid < 1:
|
||||||
|
cursinkid = int(tmplist[len(tmplist)-1])
|
||||||
|
elif len(lines[lineidx]) < 3:
|
||||||
|
break
|
||||||
|
lineidx = lineidx + 1
|
||||||
|
except Exception as einit:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-volume-error", str(einit))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-volume-error", "Error getting device ID")
|
||||||
|
|
||||||
|
return cursinkid
|
||||||
|
|
||||||
|
|
||||||
|
def keyboardevent_getvolumeinfo(deviceidstr="", defaultlevel=50, defaultmuted=0):
|
||||||
|
muted = defaultmuted
|
||||||
|
level = defaultlevel
|
||||||
|
try:
|
||||||
|
if deviceidstr == "":
|
||||||
|
audioidstr = str(keyboardevent_getvolumesinkid())
|
||||||
|
if audioidstr == "0":
|
||||||
|
debuglog("keyboard-volume-error", "Error getting device id")
|
||||||
|
return {
|
||||||
|
"level": defaultmuted,
|
||||||
|
"muted": defaultlevel
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceidstr = audioidstr
|
||||||
|
|
||||||
|
output = subprocess.check_output(["wpctl", "get-volume", deviceidstr], text=True, stderr=subprocess.DEVNULL)
|
||||||
|
debuglog("keyboard-volume-info", output)
|
||||||
|
|
||||||
|
muted = 0
|
||||||
|
level = 0
|
||||||
|
# Parse output, examples
|
||||||
|
# Volume: 0.65
|
||||||
|
# Volume: 0.55 [MUTED]
|
||||||
|
outlist = output.split()
|
||||||
|
if len(outlist) > 0:
|
||||||
|
# Get last element
|
||||||
|
tmpstr = outlist[len(outlist)-1]
|
||||||
|
# Check if muted
|
||||||
|
if "MUTE" in tmpstr:
|
||||||
|
muted = 1
|
||||||
|
if len(outlist) > 1:
|
||||||
|
tmpstr = outlist[len(outlist)-2]
|
||||||
|
if tmpstr.endswith("%"):
|
||||||
|
# Level 100% to 0%
|
||||||
|
level = int(float(tmpstr[:-1]))
|
||||||
|
elif tmpstr.replace('.', '').isdigit():
|
||||||
|
# Level 1.00 to 0.00
|
||||||
|
level = int(float(tmpstr) * 100.0)
|
||||||
|
except Exception as einit:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-volume-error", str(einit))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-volume-error", "Error getting base value")
|
||||||
|
return {
|
||||||
|
"level": defaultmuted,
|
||||||
|
"muted": defaultlevel
|
||||||
|
}
|
||||||
|
|
||||||
|
#debuglog("keyboard-volume-get", str(level)+"% Mute:"+str(muted))
|
||||||
|
|
||||||
|
return {
|
||||||
|
"level": level,
|
||||||
|
"muted": muted
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def keyboardevent_adjustvolume(baselevel, basemuted, adjustval=5):
|
||||||
|
curlevel = baselevel
|
||||||
|
curmuted = basemuted
|
||||||
|
needsnotification = False
|
||||||
|
|
||||||
|
deviceidstr = str(keyboardevent_getvolumesinkid())
|
||||||
|
if deviceidstr == "0":
|
||||||
|
debuglog("keyboard-volume-error", "Error getting device id")
|
||||||
|
return {
|
||||||
|
"level": baselevel,
|
||||||
|
"muted": basemuted
|
||||||
|
}
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# tmpobj = keyboardevent_getvolumeinfo(deviceidstr, curlevel, curmuted)
|
||||||
|
# curlevel = tmpobj["level"]
|
||||||
|
# curmuted = tmpobj["muted"]
|
||||||
|
# except Exception:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
tmpmuted = curmuted
|
||||||
|
if adjustval == 0:
|
||||||
|
# Toggle Mute
|
||||||
|
if curmuted == 0:
|
||||||
|
tmpmuted = 1
|
||||||
|
else:
|
||||||
|
tmpmuted = 0
|
||||||
|
|
||||||
|
tmpval = max(10, min(100, curlevel + adjustval))
|
||||||
|
if tmpval != curlevel:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-volume", str(curlevel)+"% to "+str(tmpval)+"%")
|
||||||
|
runcmdlist("volume", ["wpctl", "set-volume", deviceidstr, f"{tmpval}%"])
|
||||||
|
needsnotification = True
|
||||||
|
tmpmuted = 0
|
||||||
|
except Exception as adjusterr:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-volume-error", str(adjusterr))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-volume-error", "Error adjusting value")
|
||||||
|
return {
|
||||||
|
"level": curlevel,
|
||||||
|
"muted": curmuted
|
||||||
|
}
|
||||||
|
elif adjustval != 0:
|
||||||
|
# To unmute even if no volume level change
|
||||||
|
tmpmuted = 0
|
||||||
|
|
||||||
|
if tmpmuted != curmuted:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-mute", str(tmpmuted))
|
||||||
|
runcmdlist("mute", ["wpctl", "set-mute", deviceidstr, str(tmpmuted)])
|
||||||
|
needsnotification = True
|
||||||
|
except Exception as adjusterr:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-mute-error", str(adjusterr))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-mute-error", "Error adjusting value")
|
||||||
|
return {
|
||||||
|
"level": tmpval,
|
||||||
|
"muted": curmuted
|
||||||
|
}
|
||||||
|
#if tmpmuted == 1:
|
||||||
|
# notifymessage("Volume: Muted", False)
|
||||||
|
#else:
|
||||||
|
# notifymessage("Volume: "+str(tmpval)+"%", False)
|
||||||
|
|
||||||
|
# DEBUG: Checking
|
||||||
|
#keyboardevent_getvolumeinfo(deviceidstr, tmpval, tmpmuted)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"level": tmpval,
|
||||||
|
"muted": tmpmuted
|
||||||
|
}
|
||||||
|
|
||||||
|
def keyboard_getlayoutfieldvalue(tmpval):
|
||||||
|
debuglog("keyboard-layout-lang", tmpval)
|
||||||
|
if "us" in tmpval:
|
||||||
|
debuglog("keyboard-layout-langout", "us")
|
||||||
|
return "us"
|
||||||
|
debuglog("keyboard-layout-langout", "gb")
|
||||||
|
return "gb" # uk, gb, etc
|
||||||
|
#return tmpval
|
||||||
|
|
||||||
|
|
||||||
|
def keyboard_getdevicefw(kbdevice):
|
||||||
|
# info: vendor 0x6080=24704, product 0x8062=32866
|
||||||
|
try:
|
||||||
|
if kbdevice.info.vendor == 24704 and kbdevice.info.product == 32866:
|
||||||
|
# Special HID
|
||||||
|
return "314"
|
||||||
|
except Exception as infoerr:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
def keyboardevemt_keyhandler(readq):
|
||||||
|
|
||||||
|
ADJUSTTYPE_NONE=0
|
||||||
|
ADJUSTTYPE_BRIGHTNESS=1
|
||||||
|
ADJUSTTYPE_VOLUME=2
|
||||||
|
ADJUSTTYPE_MUTE=3
|
||||||
|
ADJUSTTYPE_BATTERYINFO=4
|
||||||
|
|
||||||
|
DATAREFRESHINTERVALSEC = 10
|
||||||
|
|
||||||
|
PRESSWAITINTERVALSEC = 0.5
|
||||||
|
FIRSTHOLDINTERVALSEC = 0.5
|
||||||
|
HOLDWAITINTERVALSEC = 0.5
|
||||||
|
|
||||||
|
|
||||||
|
# Get current levels
|
||||||
|
volumetime = time.time()
|
||||||
|
curvolumemuted = 0
|
||||||
|
curvolume = 50
|
||||||
|
|
||||||
|
brightnesstime = volumetime
|
||||||
|
curbrightness = 50
|
||||||
|
brightnesstoolid = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
brightnesstoolid = keyboardevent_getbrigthnesstoolid()
|
||||||
|
except Exception:
|
||||||
|
brightnesstoolid = 0
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
tmpobj = keyboardevent_getbrigthnessinfo(brightnesstoolid)
|
||||||
|
curbrightness = tmpobj["level"]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
tmpobj = keyboardevent_getvolumeinfo()
|
||||||
|
curvolumemuted = tmpobj["muted"]
|
||||||
|
curvolume = tmpobj["level"]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
tmpkeymode = 0
|
||||||
|
tmpkeycode = ""
|
||||||
|
adjustval = 0
|
||||||
|
adjusttype = ADJUSTTYPE_NONE
|
||||||
|
|
||||||
|
tmpcode = readq.get() # Blocking
|
||||||
|
try:
|
||||||
|
codeelements = tmpcode.split("+")
|
||||||
|
if len(codeelements) == 2:
|
||||||
|
if codeelements[0] == "PRESS":
|
||||||
|
tmpkeymode = 1
|
||||||
|
else:
|
||||||
|
tmpkeymode = 2
|
||||||
|
tmpkeycode = codeelements[1]
|
||||||
|
elif tmpcode == "EXIT":
|
||||||
|
readq.task_done()
|
||||||
|
return
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
tmpkeycode = ""
|
||||||
|
tmpkeymode = 0
|
||||||
|
pass
|
||||||
|
tmptime = time.time()
|
||||||
|
if tmpkeycode in [KEYCODE_BRIGHTNESSDOWN, KEYCODE_BRIGHTNESSUP]:
|
||||||
|
if tmpkeymode == 1 and tmptime - brightnesstime > DATAREFRESHINTERVALSEC:
|
||||||
|
# Do not update value during hold
|
||||||
|
try:
|
||||||
|
tmpobj = keyboardevent_getbrigthnessinfo(brightnesstoolid)
|
||||||
|
curbrightness = tmpobj["level"]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
adjusttype = ADJUSTTYPE_BRIGHTNESS
|
||||||
|
if tmpkeycode == KEYCODE_BRIGHTNESSDOWN:
|
||||||
|
adjustval = -5*tmpkeymode
|
||||||
|
else:
|
||||||
|
adjustval = 5*tmpkeymode
|
||||||
|
brightnesstime = tmptime
|
||||||
|
elif tmpkeycode in [KEYCODE_MUTE, KEYCODE_VOLUMEDOWN, KEYCODE_VOLUMEUP]:
|
||||||
|
if tmpkeymode == 1 and tmptime - volumetime > DATAREFRESHINTERVALSEC and tmpkeymode == 1:
|
||||||
|
# Do not update value during hold
|
||||||
|
try:
|
||||||
|
tmpobj = keyboardevent_getvolumeinfo()
|
||||||
|
curvolumemuted = tmpobj["muted"]
|
||||||
|
curvolume = tmpobj["level"]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if tmpkeycode == KEYCODE_MUTE:
|
||||||
|
adjusttype = ADJUSTTYPE_MUTE
|
||||||
|
adjustval = 0
|
||||||
|
else:
|
||||||
|
adjusttype = ADJUSTTYPE_VOLUME
|
||||||
|
if tmpkeycode == KEYCODE_VOLUMEDOWN:
|
||||||
|
adjustval = -5*tmpkeymode
|
||||||
|
else:
|
||||||
|
adjustval = 5*tmpkeymode
|
||||||
|
volumetime = tmptime
|
||||||
|
|
||||||
|
elif tmpkeycode == KEYCODE_PAUSE:
|
||||||
|
adjusttype = ADJUSTTYPE_BATTERYINFO
|
||||||
|
else:
|
||||||
|
readq.task_done()
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
tmplockfilea = KEYBOARD_LOCKFILE+".a"
|
||||||
|
if createlockfile(tmplockfilea) == False:
|
||||||
|
# Debug ONLY
|
||||||
|
# if tmpkeymode == 1:
|
||||||
|
# debuglog("keyboard-event", "Press Key Code: "+str(tmpkeycode))
|
||||||
|
# else:
|
||||||
|
# debuglog("keyboard-event", "Hold Key Code: "+str(tmpkeycode))
|
||||||
|
|
||||||
|
if adjusttype == ADJUSTTYPE_BRIGHTNESS:
|
||||||
|
try:
|
||||||
|
tmpobj = keyboardevent_adjustbrigthness(brightnesstoolid, curbrightness, adjustval)
|
||||||
|
curbrightness = tmpobj["level"]
|
||||||
|
except Exception as brightnesserr:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-brightnessother-error", str(brightnesserr))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-brightnessother-error", "Error adjusting value")
|
||||||
|
pass
|
||||||
|
elif adjusttype == ADJUSTTYPE_VOLUME or adjusttype == ADJUSTTYPE_MUTE:
|
||||||
|
try:
|
||||||
|
tmpobj = keyboardevent_adjustvolume(curvolume, curvolumemuted, adjustval)
|
||||||
|
curvolumemuted = tmpobj["muted"]
|
||||||
|
curvolume = tmpobj["level"]
|
||||||
|
except Exception as volumeerr:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-volumeother-error", str(volumeerr))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-volumeother-error", "Error adjusting value")
|
||||||
|
pass
|
||||||
|
elif adjusttype == ADJUSTTYPE_BATTERYINFO:
|
||||||
|
outobj = battery_loadlogdata()
|
||||||
|
try:
|
||||||
|
notifymessage(outobj["power"], False)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
deletelockfile(tmplockfilea)
|
||||||
|
|
||||||
|
|
||||||
|
except Exception as keyhandlererr:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-handlererror", str(keyhandleerr))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-handlererror", "Error")
|
||||||
|
|
||||||
|
readq.task_done()
|
||||||
|
|
||||||
|
except Exception as mainerr:
|
||||||
|
time.sleep(10)
|
||||||
|
# While True
|
||||||
|
|
||||||
|
|
||||||
|
def keyboardevent_monitor(writeq):
|
||||||
|
|
||||||
|
READTIMEOUTSECS = 1.0
|
||||||
|
|
||||||
|
FIRSTHOLDINTERVALSEC = 0.5
|
||||||
|
HOLDWAITINTERVALSEC = 0.5
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
keypresstimestamp = {}
|
||||||
|
keyholdtimestamp = {}
|
||||||
|
# Get Devices
|
||||||
|
devicelist = []
|
||||||
|
devicefdlist = []
|
||||||
|
devicepathlist = keyboardevent_getdevicepaths()
|
||||||
|
devicefwlist = []
|
||||||
|
|
||||||
|
deviceidx = 0
|
||||||
|
while deviceidx < len(devicepathlist):
|
||||||
|
try:
|
||||||
|
tmpdevice = InputDevice(devicepathlist[deviceidx])
|
||||||
|
devicelist.append(tmpdevice)
|
||||||
|
devicefdlist.append(tmpdevice.fd)
|
||||||
|
devicefwlist.append(keyboard_getdevicefw(tmpdevice))
|
||||||
|
#debuglog("keyboard-device-info", devicepathlist[deviceidx])
|
||||||
|
#debuglog("keyboard-device-info", str(tmpdevice.info))
|
||||||
|
except Exception as deverr:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-deviceerror", str(deverr)+ " "+ devicepathlist[deviceidx])
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-deviceerror", "Error "+devicepathlist[deviceidx])
|
||||||
|
deviceidx = deviceidx + 1
|
||||||
|
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-update", str(len(devicefdlist))+" Devices")
|
||||||
|
while len(devicefdlist) > 0:
|
||||||
|
# Exception when one of the devices gets removed
|
||||||
|
# Wait for events on any registered device
|
||||||
|
r, w, x = select(devicefdlist, [], [], READTIMEOUTSECS)
|
||||||
|
for fd in r:
|
||||||
|
found = False
|
||||||
|
curdevicefw = ""
|
||||||
|
deviceidx = 0
|
||||||
|
while deviceidx < len(devicefdlist):
|
||||||
|
if devicefdlist[deviceidx] == fd:
|
||||||
|
curdevicefw = devicefwlist[deviceidx]
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
deviceidx = deviceidx + 1
|
||||||
|
if found:
|
||||||
|
for event in devicelist[deviceidx].read():
|
||||||
|
try:
|
||||||
|
# Process the event
|
||||||
|
#print("Device: "+devicelist[deviceidx].path+", Event: ", event)
|
||||||
|
#debuglog("keyboard-event", "Device: "+devicelist[deviceidx].path+", Event: "+str(event))
|
||||||
|
if event.type == ecodes.EV_KEY:
|
||||||
|
key_event = categorize(event)
|
||||||
|
keycodelist = []
|
||||||
|
# 2 hold, 0 release, 1 press
|
||||||
|
if event.value == 2 or event.value == 1:
|
||||||
|
#debuglog("keyboard-event", "Mode:"+str(event.value)+" Key Code: "+str(key_event.keycode))
|
||||||
|
|
||||||
|
if isinstance(key_event.keycode, str):
|
||||||
|
keycodelist = [key_event.keycode]
|
||||||
|
else:
|
||||||
|
keycodelist = key_event.keycode
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
keycodelistidx = 0
|
||||||
|
while keycodelistidx < len(keycodelist):
|
||||||
|
tmpkeycode = keycodelist[keycodelistidx]
|
||||||
|
if curdevicefw == "314":
|
||||||
|
# Remap printscreen event as pause and vice versa for special handling
|
||||||
|
if tmpkeycode == "KEY_PRINTSCREEN":
|
||||||
|
tmpkeycode = KEYCODE_PAUSE
|
||||||
|
elif tmpkeycode == "KEY_SYSRQ":
|
||||||
|
# This gets fired for some devices
|
||||||
|
tmpkeycode = KEYCODE_PAUSE
|
||||||
|
elif tmpkeycode == KEYCODE_PAUSE:
|
||||||
|
# Some other key so it will not fire
|
||||||
|
tmpkeycode = "KEY_PRINTSCREEN"
|
||||||
|
#debuglog("keyboard-event", "FW:" + curdevicefw+ " Key Code: "+tmpkeycode + " Press:"+keycodelist[keycodelistidx])
|
||||||
|
|
||||||
|
|
||||||
|
keycodelistidx = keycodelistidx + 1
|
||||||
|
# if tmpkeycode not in [KEYCODE_BRIGHTNESSDOWN, KEYCODE_BRIGHTNESSUP, KEYCODE_VOLUMEDOWN, KEYCODE_VOLUMEUP]:
|
||||||
|
# if event.value == 2:
|
||||||
|
# # Skip hold for unhandled keys
|
||||||
|
# continue
|
||||||
|
# elif tmpkeycode not in [KEYCODE_PAUSE, KEYCODE_MUTE]:
|
||||||
|
# # Skip press for unhandled keys
|
||||||
|
# continue
|
||||||
|
if tmpkeycode not in [KEYCODE_BRIGHTNESSDOWN, KEYCODE_BRIGHTNESSUP]:
|
||||||
|
if event.value == 2:
|
||||||
|
# Skip hold for unhandled keys
|
||||||
|
continue
|
||||||
|
elif tmpkeycode not in [KEYCODE_PAUSE]:
|
||||||
|
# Skip press for unhandled keys
|
||||||
|
continue
|
||||||
|
|
||||||
|
tmptime = time.time()
|
||||||
|
finalmode = event.value
|
||||||
|
if event.value == 2:
|
||||||
|
# Hold needs checking
|
||||||
|
if tmpkeycode in keypresstimestamp:
|
||||||
|
# Guard time before first for hold
|
||||||
|
if (tmptime - keypresstimestamp[tmpkeycode]) >= FIRSTHOLDINTERVALSEC:
|
||||||
|
# Guard time for hold
|
||||||
|
if tmpkeycode in keyholdtimestamp:
|
||||||
|
if (tmptime - keyholdtimestamp[tmpkeycode]) < HOLDWAITINTERVALSEC:
|
||||||
|
#debuglog("keyboard-event", "Hold Key Code: "+str(tmpkeycode)+" - Skip")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
#debuglog("keyboard-event", "Hold Key Code: "+str(tmpkeycode)+" - Skip")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# Should not happen, but treat as if first press
|
||||||
|
finalmode = 1
|
||||||
|
|
||||||
|
#debuglog("keyboard-event", "Mode:"+str(event.value) + " Final:"+str(finalmode)+" " +str(tmpkeycode))
|
||||||
|
|
||||||
|
if finalmode == 1:
|
||||||
|
keypresstimestamp[tmpkeycode] = tmptime
|
||||||
|
writeq.put("PRESS+"+tmpkeycode)
|
||||||
|
else:
|
||||||
|
keyholdtimestamp[tmpkeycode] = tmptime
|
||||||
|
writeq.put("HOLD+"+tmpkeycode)
|
||||||
|
|
||||||
|
except Exception as keyhandleerr:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-keyerror", str(keyhandleerr))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-keyerror", "Error")
|
||||||
|
|
||||||
|
newpathlist = keyboardevent_getdevicepaths()
|
||||||
|
if keyboardevent_devicechanged(devicepathlist, newpathlist):
|
||||||
|
debuglog("keyboard-update", "Device list changed")
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-mainerror", str(e))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-mainerror", "Error")
|
||||||
|
|
||||||
|
# Close devices
|
||||||
|
while len(devicelist) > 0:
|
||||||
|
tmpdevice = devicelist.pop(0)
|
||||||
|
try:
|
||||||
|
tmpdevice.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as mainerr:
|
||||||
|
time.sleep(10)
|
||||||
|
# While True
|
||||||
|
try:
|
||||||
|
writeq.put("EXIT")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
cmd = sys.argv[1].upper()
|
||||||
|
if cmd == "SERVICE":
|
||||||
|
if createlockfile(KEYBOARD_LOCKFILE) == True:
|
||||||
|
debuglog("keyboard-service", "Already running")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-service", "Service Starting")
|
||||||
|
ipcq = Queue()
|
||||||
|
t1 = Thread(target = keyboardevemt_keyhandler, args =(ipcq, ))
|
||||||
|
t2 = Thread(target = keyboardevent_monitor, args =(ipcq, ))
|
||||||
|
t1.start()
|
||||||
|
t2.start()
|
||||||
|
|
||||||
|
ipcq.join()
|
||||||
|
|
||||||
|
except Exception as einit:
|
||||||
|
try:
|
||||||
|
debuglog("keyboard-service-error", str(einit))
|
||||||
|
except:
|
||||||
|
debuglog("keyboard-service-error", "Error")
|
||||||
|
debuglog("keyboard-service", "Service Stopped")
|
||||||
|
deletelockfile(KEYBOARD_LOCKFILE)
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
daemonconfigfile=/etc/argononed.conf
|
||||||
|
unitconfigfile=/etc/argonunits.conf
|
||||||
|
fanmode="CPU"
|
||||||
|
|
||||||
|
if [ "$1" == "hdd" ]
|
||||||
|
then
|
||||||
|
daemonconfigfile=/etc/argononed-hdd.conf
|
||||||
|
fanmode="HDD"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -f "$unitconfigfile" ]
|
||||||
|
then
|
||||||
|
. $unitconfigfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$temperature" ]
|
||||||
|
then
|
||||||
|
temperature="C"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "------------------------------------------"
|
||||||
|
echo " Argon Fan Speed Configuration Tool ($fanmode)"
|
||||||
|
echo "------------------------------------------"
|
||||||
|
echo "WARNING: This will remove existing configuration."
|
||||||
|
echo -n "Press Y to continue:"
|
||||||
|
read -n 1 confirm
|
||||||
|
echo
|
||||||
|
|
||||||
|
|
||||||
|
fanloopflag=1
|
||||||
|
newmode=0
|
||||||
|
if [ "$confirm" = "y" ]
|
||||||
|
then
|
||||||
|
confirm="Y"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$confirm" != "Y" ]
|
||||||
|
then
|
||||||
|
fanloopflag=0
|
||||||
|
echo "Cancelled."
|
||||||
|
else
|
||||||
|
echo "Thank you."
|
||||||
|
fi
|
||||||
|
|
||||||
|
get_number () {
|
||||||
|
read curnumber
|
||||||
|
if [ -z "$curnumber" ]
|
||||||
|
then
|
||||||
|
echo "-2"
|
||||||
|
return
|
||||||
|
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||||
|
then
|
||||||
|
if [ $curnumber -lt 0 ]
|
||||||
|
then
|
||||||
|
echo "-1"
|
||||||
|
return
|
||||||
|
elif [ $curnumber -gt 212 ]
|
||||||
|
then
|
||||||
|
# 212F = 100C
|
||||||
|
echo "-1"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo $curnumber
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo "-1"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
while [ $fanloopflag -eq 1 ]
|
||||||
|
do
|
||||||
|
echo
|
||||||
|
echo "Select fan mode:"
|
||||||
|
echo " 1. Always on"
|
||||||
|
if [ "$fanmode" == "HDD" ]
|
||||||
|
then
|
||||||
|
if [ "$temperature" == "C" ]
|
||||||
|
then
|
||||||
|
echo " 2. Adjust to temperatures (35C, 40C, and 45C)"
|
||||||
|
else
|
||||||
|
echo " 2. Adjust to temperatures (95F, 104F, and 113F)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ "$temperature" == "C" ]
|
||||||
|
then
|
||||||
|
echo " 2. Adjust to temperatures (55C, 60C, and 65C)"
|
||||||
|
else
|
||||||
|
echo " 2. Adjust to temperatures (130F, 140F, and 150F)"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
echo " 3. Customize temperature cut-offs"
|
||||||
|
echo
|
||||||
|
echo " 0. Exit"
|
||||||
|
echo "NOTE: You can also edit $daemonconfigfile directly"
|
||||||
|
echo -n "Enter Number (0-3):"
|
||||||
|
newmode=$( get_number )
|
||||||
|
|
||||||
|
if [[ $newmode -eq 0 ]]
|
||||||
|
then
|
||||||
|
fanloopflag=0
|
||||||
|
elif [ $newmode -eq 1 ]
|
||||||
|
then
|
||||||
|
echo "#" > $daemonconfigfile
|
||||||
|
echo "# Argon Fan Speed Configuration $fanmode" >> $daemonconfigfile
|
||||||
|
echo "#" >> $daemonconfigfile
|
||||||
|
echo "# Min Temp=Fan Speed" >> $daemonconfigfile
|
||||||
|
|
||||||
|
errorfanflag=1
|
||||||
|
while [ $errorfanflag -eq 1 ]
|
||||||
|
do
|
||||||
|
echo -n "Please provide fan speed (30-100 only):"
|
||||||
|
|
||||||
|
curfan=$( get_number )
|
||||||
|
if [ $curfan -ge 30 ]
|
||||||
|
then
|
||||||
|
errorfanflag=0
|
||||||
|
elif [ $curfan -gt 100 ]
|
||||||
|
then
|
||||||
|
errorfanflag=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "1="$curfan >> $daemonconfigfile
|
||||||
|
sudo systemctl restart argononed.service
|
||||||
|
echo "Fan always on."
|
||||||
|
elif [ $newmode -eq 2 ]
|
||||||
|
then
|
||||||
|
echo "#" > $daemonconfigfile
|
||||||
|
echo "# Argon Fan Speed Configuration $fanmode" >> $daemonconfigfile
|
||||||
|
echo "#" >> $daemonconfigfile
|
||||||
|
echo "# Min Temp=Fan Speed" >> $daemonconfigfile
|
||||||
|
|
||||||
|
echo "Please provide fan speeds for the following temperatures:"
|
||||||
|
curtemp=55
|
||||||
|
maxtemp=70
|
||||||
|
if [ "$fanmode" == "HDD" ]
|
||||||
|
then
|
||||||
|
curtemp=30
|
||||||
|
maxtemp=60
|
||||||
|
fi
|
||||||
|
while [ $curtemp -lt $maxtemp ]
|
||||||
|
do
|
||||||
|
errorfanflag=1
|
||||||
|
while [ $errorfanflag -eq 1 ]
|
||||||
|
do
|
||||||
|
displaytemp=$curtemp
|
||||||
|
if [ "$temperature" == "F" ]
|
||||||
|
then
|
||||||
|
# Convert C to F
|
||||||
|
displaytemp=$((($curtemp*9/5)+32))
|
||||||
|
fi
|
||||||
|
echo -n ""$displaytemp"$temperature (30-100 only):"
|
||||||
|
|
||||||
|
curfan=$( get_number )
|
||||||
|
if [ $curfan -ge 30 ]
|
||||||
|
then
|
||||||
|
errorfanflag=0
|
||||||
|
elif [ $curfan -gt 100 ]
|
||||||
|
then
|
||||||
|
errorfanflag=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo $curtemp"="$curfan >> $daemonconfigfile
|
||||||
|
curtemp=$((curtemp+5))
|
||||||
|
done
|
||||||
|
|
||||||
|
sudo systemctl restart argononed.service
|
||||||
|
echo "Configuration updated."
|
||||||
|
elif [ $newmode -eq 3 ]
|
||||||
|
then
|
||||||
|
echo "Please provide fan speeds and temperature pairs"
|
||||||
|
echo
|
||||||
|
|
||||||
|
subloopflag=1
|
||||||
|
paircounter=0
|
||||||
|
while [ $subloopflag -eq 1 ]
|
||||||
|
do
|
||||||
|
errortempflag=1
|
||||||
|
errorfanflag=1
|
||||||
|
echo "(You may set a blank value to end configuration)"
|
||||||
|
while [ $errortempflag -eq 1 ]
|
||||||
|
do
|
||||||
|
echo -n "Provide minimum temperature of $fanmode (in $temperature) then [ENTER]:"
|
||||||
|
|
||||||
|
curtemp=$( get_number )
|
||||||
|
if [ $curtemp -ge 0 ]
|
||||||
|
then
|
||||||
|
errortempflag=0
|
||||||
|
elif [ $curtemp -eq -2 ]
|
||||||
|
then
|
||||||
|
# Blank
|
||||||
|
errortempflag=0
|
||||||
|
errorfanflag=0
|
||||||
|
subloopflag=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
while [ $errorfanflag -eq 1 ]
|
||||||
|
do
|
||||||
|
echo -n "Provide fan speed for "$curtemp"$temperature (30-100) then [ENTER]:"
|
||||||
|
curfan=$( get_number )
|
||||||
|
if [ $curfan -ge 30 ]
|
||||||
|
then
|
||||||
|
errorfanflag=0
|
||||||
|
elif [ $curfan -gt 100 ]
|
||||||
|
then
|
||||||
|
errorfanflag=0
|
||||||
|
elif [ $curfan -eq -2 ]
|
||||||
|
then
|
||||||
|
# Blank
|
||||||
|
errortempflag=0
|
||||||
|
errorfanflag=0
|
||||||
|
subloopflag=0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ $subloopflag -eq 1 ]
|
||||||
|
then
|
||||||
|
if [ $paircounter -eq 0 ]
|
||||||
|
then
|
||||||
|
echo "#" > $daemonconfigfile
|
||||||
|
echo "# Argon Fan Configuration" >> $daemonconfigfile
|
||||||
|
echo "#" >> $daemonconfigfile
|
||||||
|
echo "# Min Temp=Fan Speed" >> $daemonconfigfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
displaytemp=$curtemp
|
||||||
|
paircounter=$((paircounter+1))
|
||||||
|
if [ "$temperature" == "F" ]
|
||||||
|
then
|
||||||
|
# Convert to F to C
|
||||||
|
curtemp=$((($curtemp-32)*5/9))
|
||||||
|
fi
|
||||||
|
echo $curtemp"="$curfan >> $daemonconfigfile
|
||||||
|
|
||||||
|
echo "* Fan speed will be set to "$curfan" once $fanmode temperature reaches "$displaytemp"$temperature"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
if [ $paircounter -gt 0 ]
|
||||||
|
then
|
||||||
|
echo "Thank you! We saved "$paircounter" pairs."
|
||||||
|
sudo systemctl restart argononed.service
|
||||||
|
echo "Changes should take effect now."
|
||||||
|
else
|
||||||
|
echo "Cancelled, no data saved."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
if [ -e /boot/firmware/config.txt ] ; then
|
if [ -e /boot/firmware/config.txt ] ; then
|
||||||
FIRMWARE=/firmware
|
FIRMWARE=/firmware
|
||||||
else
|
else
|
||||||
@@ -24,9 +25,10 @@ then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "--------------------------------"
|
|
||||||
echo "Argon One IR Configuration Tool"
|
echo "-----------------------------"
|
||||||
echo "--------------------------------"
|
echo " Argon IR Configuration Tool"
|
||||||
|
echo "------------------------------"
|
||||||
echo "WARNING: This only supports NEC"
|
echo "WARNING: This only supports NEC"
|
||||||
echo " protocol only."
|
echo " protocol only."
|
||||||
echo -n "Press Y to continue:"
|
echo -n "Press Y to continue:"
|
||||||
@@ -70,8 +72,8 @@ get_number () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
irexecrcfile=/etc/lirc/irexec.lircrc
|
irexecrcfile=/etc/lirc/irexec.lircrc
|
||||||
irexecshfile=/usr/bin/argonirexec
|
irexecshfile=/etc/argon/argonirexec
|
||||||
irdecodefile=/usr/bin/argonirdecoder
|
irdecodefile=/etc/argon/argonirdecoder
|
||||||
kodiuserdatafolder="$HOME/.kodi/userdata"
|
kodiuserdatafolder="$HOME/.kodi/userdata"
|
||||||
kodilircmapfile="$kodiuserdatafolder/Lircmap.xml"
|
kodilircmapfile="$kodiuserdatafolder/Lircmap.xml"
|
||||||
remotemode=""
|
remotemode=""
|
||||||
@@ -176,9 +178,9 @@ then
|
|||||||
fi
|
fi
|
||||||
elif [ $newmode -eq 2 ]
|
elif [ $newmode -eq 2 ]
|
||||||
then
|
then
|
||||||
echo "--------------------------------"
|
echo "-----------------------------"
|
||||||
echo "Argon One IR Configuration Tool"
|
echo " Argon IR Configuration Tool"
|
||||||
echo "--------------------------------"
|
echo "-----------------------------"
|
||||||
echo "WARNING: This will install LIRC"
|
echo "WARNING: This will install LIRC"
|
||||||
echo " and related libraries."
|
echo " and related libraries."
|
||||||
echo -n "Press Y to agree:"
|
echo -n "Press Y to agree:"
|
||||||
@@ -320,7 +322,10 @@ then
|
|||||||
echo ' <down>KEY_DOWN</down>' | tee -a $kodilircmapfile 1> /dev/null
|
echo ' <down>KEY_DOWN</down>' | tee -a $kodilircmapfile 1> /dev/null
|
||||||
echo ' <select>KEY_OK</select>' | 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 ' <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 ' <volumeplus>KEY_VOLUMEUP</volumeplus>' | tee -a $kodilircmapfile 1> /dev/null
|
||||||
echo ' <volumeminus>KEY_VOLUMEDOWN</volumeminus>' | 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
|
echo ' </remote>' | tee -a $kodilircmapfile 1> /dev/null
|
||||||
@@ -0,0 +1,525 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
# Standard Headers
|
||||||
|
import sys
|
||||||
|
import smbus
|
||||||
|
|
||||||
|
# For GPIO
|
||||||
|
import gpiod
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Check if Lirc Lib is installed
|
||||||
|
haslirclib = os.path.isfile("/usr/bin/mode2")
|
||||||
|
if haslirclib == True:
|
||||||
|
from multiprocessing import Process
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# Use GPIO
|
||||||
|
|
||||||
|
def getGPIOPulseData():
|
||||||
|
# Counter
|
||||||
|
ctr = 0
|
||||||
|
|
||||||
|
# Pin Assignments
|
||||||
|
LINE_IRRECEIVER=23
|
||||||
|
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
# Pi5 mapping
|
||||||
|
chip = gpiod.Chip('4')
|
||||||
|
except Exception as gpioerr:
|
||||||
|
# Old mapping
|
||||||
|
chip = gpiod.Chip('0')
|
||||||
|
lineobj = chip.get_line(LINE_IRRECEIVER)
|
||||||
|
lineobj.request(consumer="argon", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||||
|
except Exception as e:
|
||||||
|
# GPIO Error
|
||||||
|
return [(-2, -2)]
|
||||||
|
|
||||||
|
# Start reading
|
||||||
|
value = lineobj.get_value()
|
||||||
|
|
||||||
|
# mark time
|
||||||
|
startTime = datetime.now()
|
||||||
|
pulseTime = startTime
|
||||||
|
|
||||||
|
# Pulse Data
|
||||||
|
pulsedata = []
|
||||||
|
|
||||||
|
aborted = False
|
||||||
|
while aborted == False:
|
||||||
|
# Wait for transition
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
hasevent = lineobj.event_wait(10)
|
||||||
|
if hasevent:
|
||||||
|
# Event data needs to be read
|
||||||
|
eventdata = lineobj.event_read()
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
# GPIO Error
|
||||||
|
lineobj.release()
|
||||||
|
chip.close()
|
||||||
|
return [(-2, -2)]
|
||||||
|
|
||||||
|
# high/low Length
|
||||||
|
now = datetime.now()
|
||||||
|
pulseLength = now - pulseTime
|
||||||
|
pulseTime = now
|
||||||
|
|
||||||
|
# Update value (changed triggered), this also inverts value before saving
|
||||||
|
if value:
|
||||||
|
value = 0
|
||||||
|
else:
|
||||||
|
value = 1
|
||||||
|
|
||||||
|
if pulseLength.microseconds > PULSETAIL_MAXMICROS_NEC and ctr == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
pulsedata.append((value, pulseLength.microseconds))
|
||||||
|
|
||||||
|
ctr = ctr + 1
|
||||||
|
if pulseLength.microseconds > PULSETAIL_MAXMICROS_NEC:
|
||||||
|
break
|
||||||
|
elif ctr > PULSEDATA_MAXCOUNT:
|
||||||
|
break
|
||||||
|
|
||||||
|
lineobj.release()
|
||||||
|
chip.close()
|
||||||
|
|
||||||
|
# Data is most likely incomplete
|
||||||
|
if aborted == True:
|
||||||
|
return []
|
||||||
|
elif ctr >= PULSEDATA_MAXCOUNT:
|
||||||
|
print (" * Unable to decode. Please try again *")
|
||||||
|
return []
|
||||||
|
return pulsedata
|
||||||
|
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# Use LIRC
|
||||||
|
def lircMode2Task(irlogfile):
|
||||||
|
os.system("mode2 > "+irlogfile+" 2>&1")
|
||||||
|
|
||||||
|
def startLIRCMode2Logging(irlogfile):
|
||||||
|
# create a new process
|
||||||
|
loggerprocess = Process(target=lircMode2Task,args=(irlogfile,))
|
||||||
|
loggerprocess.start()
|
||||||
|
# mode2 will start new process, terminate current
|
||||||
|
time.sleep(0.1)
|
||||||
|
loggerprocess.kill()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def endLIRCMode2Logging(irlogfile):
|
||||||
|
tmplogfile = irlogfile+".tmp"
|
||||||
|
os.system("ps | grep ode2 > "+tmplogfile+"")
|
||||||
|
|
||||||
|
if os.path.exists(tmplogfile) == True:
|
||||||
|
ctr = 0
|
||||||
|
fp = open(tmplogfile, "r")
|
||||||
|
for curline in fp:
|
||||||
|
if len(curline) > 0:
|
||||||
|
rowdata = curline.split(" ")
|
||||||
|
pid = ""
|
||||||
|
processname = ""
|
||||||
|
colidx = 0
|
||||||
|
while colidx < len(rowdata):
|
||||||
|
if len(rowdata[colidx]) > 0:
|
||||||
|
if pid == "":
|
||||||
|
pid = rowdata[colidx]
|
||||||
|
else:
|
||||||
|
processname = rowdata[colidx]
|
||||||
|
|
||||||
|
colidx = colidx + 1
|
||||||
|
if processname=="mode2\n":
|
||||||
|
os.system("kill -9 "+pid)
|
||||||
|
fp.close()
|
||||||
|
os.remove(tmplogfile)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def getLIRCPulseData():
|
||||||
|
if haslirclib == False:
|
||||||
|
print (" * LIRC Module not found, please reboot and try again *")
|
||||||
|
return []
|
||||||
|
|
||||||
|
irlogfile = "/dev/shm/lircdecoder.log"
|
||||||
|
|
||||||
|
loggerresult = startLIRCMode2Logging(irlogfile)
|
||||||
|
if loggerresult == False:
|
||||||
|
return [(-1, -1)]
|
||||||
|
|
||||||
|
# Wait for log file
|
||||||
|
logsize = 0
|
||||||
|
while logsize == 0:
|
||||||
|
if os.path.exists(irlogfile) == True:
|
||||||
|
logsize = os.path.getsize(irlogfile)
|
||||||
|
if logsize == 0:
|
||||||
|
time.sleep(0.1)
|
||||||
|
|
||||||
|
# Wait for data to start
|
||||||
|
newlogsize = logsize
|
||||||
|
while logsize == newlogsize:
|
||||||
|
time.sleep(0.1)
|
||||||
|
newlogsize = os.path.getsize(irlogfile)
|
||||||
|
|
||||||
|
print(" Thank you")
|
||||||
|
|
||||||
|
# Wait for data to stop
|
||||||
|
while logsize != newlogsize:
|
||||||
|
logsize = newlogsize
|
||||||
|
time.sleep(0.1)
|
||||||
|
newlogsize = os.path.getsize(irlogfile)
|
||||||
|
|
||||||
|
# Finalize File
|
||||||
|
loggerresult = endLIRCMode2Logging(irlogfile)
|
||||||
|
if loggerresult == False:
|
||||||
|
return [(-1, -1)]
|
||||||
|
|
||||||
|
# Decode logfile into Pulse Data
|
||||||
|
pulsedata = []
|
||||||
|
|
||||||
|
terminated = False
|
||||||
|
if os.path.exists(irlogfile) == True:
|
||||||
|
ctr = 0
|
||||||
|
fp = open(irlogfile, "r")
|
||||||
|
for curline in fp:
|
||||||
|
if len(curline) > 0:
|
||||||
|
rowdata = curline.split(" ")
|
||||||
|
if len(rowdata) == 2:
|
||||||
|
duration = int(rowdata[1])
|
||||||
|
value = 0
|
||||||
|
if rowdata[0] == "pulse":
|
||||||
|
value = 1
|
||||||
|
ctr = ctr + 1
|
||||||
|
if value == 1 or ctr > 1:
|
||||||
|
if len(pulsedata) > 0 and duration > PULSELEADER_MINMICROS_NEC:
|
||||||
|
terminated = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
pulsedata.append((value, duration))
|
||||||
|
fp.close()
|
||||||
|
os.remove(irlogfile)
|
||||||
|
|
||||||
|
# Check if terminating pulse detected
|
||||||
|
if terminated == False:
|
||||||
|
print (" * Unable to read signal. Please try again *")
|
||||||
|
return []
|
||||||
|
return pulsedata
|
||||||
|
|
||||||
|
|
||||||
|
#########################
|
||||||
|
# Common
|
||||||
|
irconffile = "/etc/lirc/lircd.conf.d/argon.lircd.conf"
|
||||||
|
|
||||||
|
# I2C
|
||||||
|
address = 0x1a # I2C Address
|
||||||
|
addressregister = 0xaa # I2C Address Register
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
PULSETIMEOUTMS = 1000
|
||||||
|
VERIFYTARGET = 3
|
||||||
|
PULSEDATA_MAXCOUNT = 200 # Fail safe
|
||||||
|
|
||||||
|
# NEC Protocol Constants
|
||||||
|
PULSEBIT_MAXMICROS_NEC = 2500
|
||||||
|
PULSEBIT_ZEROMICROS_NEC = 1000
|
||||||
|
|
||||||
|
PULSELEADER_MINMICROS_NEC = 8000
|
||||||
|
PULSELEADER_MAXMICROS_NEC = 10000
|
||||||
|
PULSETAIL_MAXMICROS_NEC = 12000
|
||||||
|
|
||||||
|
# Flags
|
||||||
|
FLAGV1ONLY = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
if os.path.isfile("/etc/argon/flag_v1"):
|
||||||
|
FLAGV1ONLY = True
|
||||||
|
except Exception:
|
||||||
|
FLAGV1ONLY = False
|
||||||
|
|
||||||
|
|
||||||
|
# Standard Methods
|
||||||
|
def getbytestring(pulsedata):
|
||||||
|
outstring = ""
|
||||||
|
for curbyte in pulsedata:
|
||||||
|
tmpstr = hex(curbyte)[2:]
|
||||||
|
while len(tmpstr) < 2:
|
||||||
|
tmpstr = "0" + tmpstr
|
||||||
|
outstring = outstring+tmpstr
|
||||||
|
return outstring
|
||||||
|
|
||||||
|
def displaybyte(pulsedata):
|
||||||
|
print (getbytestring(pulsedata))
|
||||||
|
|
||||||
|
|
||||||
|
def pulse2byteNEC(pulsedata):
|
||||||
|
outdata = []
|
||||||
|
bitdata = 1
|
||||||
|
curbyte = 0
|
||||||
|
bitcount = 0
|
||||||
|
for (mode, duration) in pulsedata:
|
||||||
|
if mode == 1:
|
||||||
|
continue
|
||||||
|
elif duration > PULSEBIT_MAXMICROS_NEC:
|
||||||
|
continue
|
||||||
|
elif duration > PULSEBIT_ZEROMICROS_NEC:
|
||||||
|
curbyte = curbyte*2 + 1
|
||||||
|
else:
|
||||||
|
curbyte = curbyte*2
|
||||||
|
|
||||||
|
bitcount = bitcount + 1
|
||||||
|
if bitcount == 8:
|
||||||
|
outdata.append(curbyte)
|
||||||
|
curbyte = 0
|
||||||
|
bitcount = 0
|
||||||
|
# Shouldn't happen, but just in case
|
||||||
|
if bitcount > 0:
|
||||||
|
outdata.append(curbyte)
|
||||||
|
|
||||||
|
return outdata
|
||||||
|
|
||||||
|
|
||||||
|
def bytecompare(a, b):
|
||||||
|
idx = 0
|
||||||
|
maxidx = len(a)
|
||||||
|
if maxidx != len(b):
|
||||||
|
return 1
|
||||||
|
while idx < maxidx:
|
||||||
|
if a[idx] != b[idx]:
|
||||||
|
return 1
|
||||||
|
idx = idx + 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
# Main Flow
|
||||||
|
mode = "custom"
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
mode = sys.argv[1]
|
||||||
|
|
||||||
|
powerdata = []
|
||||||
|
buttonlist = ['POWER', 'UP', 'DOWN', 'LEFT', 'RIGHT',
|
||||||
|
'VOLUMEUP', 'VOLUMEDOWN', 'OK', 'HOME', 'MENU'
|
||||||
|
'BACK']
|
||||||
|
|
||||||
|
ircodelist = ['00ff39c6', '00ff53ac', '00ff4bb4', '00ff9966', '00ff837c',
|
||||||
|
'00ff01fe', '00ff817e', '00ff738c', '00ffd32c', '00ffb946',
|
||||||
|
'00ff09f6']
|
||||||
|
|
||||||
|
buttonidx = 0
|
||||||
|
|
||||||
|
if mode == "power":
|
||||||
|
buttonlist = ['POWER']
|
||||||
|
ircodelist = ['']
|
||||||
|
elif mode == "resetpower":
|
||||||
|
# Just Set the power so it won't create/update the conf file
|
||||||
|
buttonlist = ['POWER']
|
||||||
|
mode = "default"
|
||||||
|
elif mode == "custom":
|
||||||
|
buttonlist = ['POWER', 'UP', 'DOWN', 'LEFT', 'RIGHT',
|
||||||
|
'VOLUMEUP', 'VOLUMEDOWN', 'OK', 'HOME', 'MENU'
|
||||||
|
'BACK']
|
||||||
|
ircodelist = ['', '', '', '', '',
|
||||||
|
'', '', '', '', '',
|
||||||
|
'']
|
||||||
|
#buttonlist = ['POWER', 'VOLUMEUP', 'VOLUMEDOWN']
|
||||||
|
#ircodelist = ['', '', '']
|
||||||
|
|
||||||
|
if mode == "default":
|
||||||
|
# To skip the decoding loop
|
||||||
|
buttonidx = len(buttonlist)
|
||||||
|
# Set MCU IR code
|
||||||
|
powerdata = [0x00, 0xff, 0x39, 0xc6]
|
||||||
|
else:
|
||||||
|
print ("************************************************")
|
||||||
|
print ("* WARNING: Current buttons are still active. *")
|
||||||
|
print ("* Please temporarily assign to a *")
|
||||||
|
print ("* different button if you plan to *")
|
||||||
|
print ("* reuse buttons. *")
|
||||||
|
print ("* e.g. Power Button triggers shutdown *")
|
||||||
|
print ("* *")
|
||||||
|
print ("* PROCEED AT YOUR OWN RISK *")
|
||||||
|
print ("* (Press CTRL+C to abort at any time) *")
|
||||||
|
print ("************************************************")
|
||||||
|
|
||||||
|
readaborted = False
|
||||||
|
# decoding loop
|
||||||
|
while buttonidx < len(buttonlist):
|
||||||
|
print ("Press your button for "+buttonlist[buttonidx]+" (CTRL+C to abort)")
|
||||||
|
irprotocol = ""
|
||||||
|
outdata = []
|
||||||
|
verifycount = 0
|
||||||
|
readongoing = True
|
||||||
|
|
||||||
|
# Handles NEC protocol Only
|
||||||
|
while readongoing == True:
|
||||||
|
# Try GPIO-based reading, if it fails, fallback to LIRC
|
||||||
|
pulsedata = getGPIOPulseData()
|
||||||
|
if len(pulsedata) == 1:
|
||||||
|
if pulsedata[0][0] == -2:
|
||||||
|
pulsedata = getLIRCPulseData()
|
||||||
|
|
||||||
|
# Aborted
|
||||||
|
if len(pulsedata) == 1:
|
||||||
|
if pulsedata[0][0] == -1:
|
||||||
|
readongoing = False
|
||||||
|
readaborted = True
|
||||||
|
buttonidx = len(buttonlist)
|
||||||
|
break
|
||||||
|
# Ignore repeat code (NEC)
|
||||||
|
if len(pulsedata) <= 4:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Get leading signal
|
||||||
|
(mode, duration) = pulsedata[0]
|
||||||
|
|
||||||
|
# Decode IR Protocols
|
||||||
|
# https://www.sbprojects.net/knowledge/ir/index.php
|
||||||
|
|
||||||
|
if duration >= PULSELEADER_MINMICROS_NEC and duration <= PULSELEADER_MAXMICROS_NEC:
|
||||||
|
irprotocol = "NEC"
|
||||||
|
# NEC has 9ms head, +/- 1ms
|
||||||
|
curdata = pulse2byteNEC(pulsedata)
|
||||||
|
if len(curdata) > 0:
|
||||||
|
if verifycount > 0:
|
||||||
|
if bytecompare(outdata, curdata) == 0:
|
||||||
|
verifycount = verifycount + 1
|
||||||
|
else:
|
||||||
|
verifycount = 0
|
||||||
|
else:
|
||||||
|
outdata = curdata
|
||||||
|
verifycount = 1
|
||||||
|
|
||||||
|
if verifycount >= VERIFYTARGET:
|
||||||
|
readongoing = False
|
||||||
|
print ("")
|
||||||
|
elif verifycount == 0:
|
||||||
|
print (" * IR code mismatch, please try again *")
|
||||||
|
elif VERIFYTARGET - verifycount > 1:
|
||||||
|
print (" Press the button "+ str(VERIFYTARGET - verifycount)+ " more times")
|
||||||
|
else:
|
||||||
|
print (" Press the button 1 more time")
|
||||||
|
else:
|
||||||
|
print (" * Decoding error. Please try again *")
|
||||||
|
else:
|
||||||
|
print (" * Unrecognized signal. Please try again *")
|
||||||
|
#curdata = pulse2byteLSB(pulsedata)
|
||||||
|
#displaybyte(curdata)
|
||||||
|
|
||||||
|
# Check for duplicates
|
||||||
|
newircode = getbytestring(outdata)
|
||||||
|
if verifycount > 0:
|
||||||
|
checkidx = 0
|
||||||
|
while checkidx < buttonidx and checkidx < len(buttonlist):
|
||||||
|
if ircodelist[checkidx] == newircode:
|
||||||
|
print (" Button already assigned. Please try again")
|
||||||
|
verifycount = 0
|
||||||
|
break
|
||||||
|
checkidx = checkidx + 1
|
||||||
|
|
||||||
|
# Store code, and power button code if applicable
|
||||||
|
if verifycount > 0:
|
||||||
|
if buttonidx == 0:
|
||||||
|
powerdata = outdata
|
||||||
|
if buttonidx < len(buttonlist):
|
||||||
|
# Abort will cause out of bounds
|
||||||
|
ircodelist[buttonidx] = newircode
|
||||||
|
#print (buttonlist[buttonidx]+": "+ newircode)
|
||||||
|
buttonidx = buttonidx + 1
|
||||||
|
|
||||||
|
if len(powerdata) > 0 and readaborted == False:
|
||||||
|
# Send to device if completed or reset mode
|
||||||
|
#print("Writing " + getbytestring(powerdata))
|
||||||
|
print("Updating Device...")
|
||||||
|
try:
|
||||||
|
bus=smbus.SMBus(1)
|
||||||
|
except Exception:
|
||||||
|
try:
|
||||||
|
# Older version
|
||||||
|
bus=smbus.SMBus(0)
|
||||||
|
except Exception:
|
||||||
|
bus=None
|
||||||
|
|
||||||
|
if bus is None:
|
||||||
|
print("Device Update Failed: Unable to detect i2c")
|
||||||
|
else:
|
||||||
|
# Check for Argon Control Register Support
|
||||||
|
checkircodewrite = False
|
||||||
|
argoncyclereg = 0x80
|
||||||
|
if FLAGV1ONLY == False:
|
||||||
|
oldval = bus.read_byte_data(address, argoncyclereg)
|
||||||
|
newval = oldval + 1
|
||||||
|
if newval >= 100:
|
||||||
|
newval = 98
|
||||||
|
bus.write_byte_data(address,argoncyclereg, newval)
|
||||||
|
time.sleep(1)
|
||||||
|
newval = bus.read_byte_data(address, argoncyclereg)
|
||||||
|
|
||||||
|
if newval != oldval:
|
||||||
|
addressregister = 0x82
|
||||||
|
checkircodewrite = True
|
||||||
|
bus.write_byte_data(address,argoncyclereg, oldval)
|
||||||
|
|
||||||
|
bus.write_i2c_block_data(address, addressregister, powerdata)
|
||||||
|
|
||||||
|
|
||||||
|
if checkircodewrite == True:
|
||||||
|
# Check if data was written for devices that support it
|
||||||
|
print("Verifying ...")
|
||||||
|
time.sleep(2)
|
||||||
|
checkircodedata = bus.read_i2c_block_data(address, addressregister, 4)
|
||||||
|
checkircodecounter = 0
|
||||||
|
while checkircodecounter < 4:
|
||||||
|
# Reuse readaborted flag as indicator if IR code was successfully updated
|
||||||
|
if checkircodedata[checkircodecounter] != powerdata[checkircodecounter]:
|
||||||
|
readaborted = True
|
||||||
|
checkircodecounter = checkircodecounter + 1
|
||||||
|
if readaborted == False:
|
||||||
|
print("Device Update Successful")
|
||||||
|
else:
|
||||||
|
print("Verification Failed")
|
||||||
|
bus.close()
|
||||||
|
|
||||||
|
# Update IR Conf if there are other button
|
||||||
|
if buttonidx > 1 and readaborted == False:
|
||||||
|
print("Updating Remote Control Codes...")
|
||||||
|
fp = open(irconffile, "w")
|
||||||
|
|
||||||
|
# Standard NEC conf header
|
||||||
|
fp.write("#\n")
|
||||||
|
fp.write("# Based on NEC templates at http://lirc.sourceforge.net/remotes/nec/\n")
|
||||||
|
fp.write("# Configured codes based on data gathered\n")
|
||||||
|
fp.write("#\n")
|
||||||
|
fp.write("\n")
|
||||||
|
fp.write("begin remote\n")
|
||||||
|
fp.write(" name argon\n")
|
||||||
|
fp.write(" bits 32\n")
|
||||||
|
fp.write(" flags SPACE_ENC\n")
|
||||||
|
fp.write(" eps 20\n")
|
||||||
|
fp.write(" aeps 200\n")
|
||||||
|
fp.write("\n")
|
||||||
|
fp.write(" header 8800 4400\n")
|
||||||
|
fp.write(" one 550 1650\n")
|
||||||
|
fp.write(" zero 550 550\n")
|
||||||
|
fp.write(" ptrail 550\n")
|
||||||
|
fp.write(" repeat 8800 2200\n")
|
||||||
|
fp.write(" gap 38500\n")
|
||||||
|
fp.write(" toggle_bit 0\n")
|
||||||
|
fp.write("\n")
|
||||||
|
fp.write(" frequency 38000\n")
|
||||||
|
fp.write("\n")
|
||||||
|
fp.write(" begin codes\n")
|
||||||
|
|
||||||
|
# Write Key Codes
|
||||||
|
buttonidx = 1
|
||||||
|
while buttonidx < len(buttonlist):
|
||||||
|
fp.write(" KEY_"+buttonlist[buttonidx]+" 0x"+ircodelist[buttonidx]+"\n")
|
||||||
|
buttonidx = buttonidx + 1
|
||||||
|
fp.write(" end codes\n")
|
||||||
|
fp.write("end remote\n")
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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" == "ram" ]
|
||||||
|
then
|
||||||
|
pagename="Available RAM"
|
||||||
|
elif [ "$1" == "temp" ]
|
||||||
|
then
|
||||||
|
pagename="CPU Temperature"
|
||||||
|
elif [ "$1" == "ip" ]
|
||||||
|
then
|
||||||
|
pagename="IP Address"
|
||||||
|
elif [ "$1" == "logo1v5" ]
|
||||||
|
then
|
||||||
|
pagename="Logo:One v5"
|
||||||
|
else
|
||||||
|
pagename="Invalid"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
configure_pagelist () {
|
||||||
|
pagemasterlist="logo1v5 clock cpu storage 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="ip cpu ram"
|
||||||
|
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
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
#!/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
|
||||||
|
if [ ! -z "$1" ]
|
||||||
|
then
|
||||||
|
requireinstall=1
|
||||||
|
newmode=3 # installation
|
||||||
|
fi
|
||||||
|
|
||||||
|
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" ] && [ -f "$rtcconfigscript" ]
|
||||||
|
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
|
||||||
|
|
||||||
|
if [ ! -z "$1" ]
|
||||||
|
then
|
||||||
|
# Called from setup script
|
||||||
|
loopflag=0
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,619 @@
|
|||||||
|
#!/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"
|
||||||
|
|
||||||
|
SHUTDOWN_FLAGFILE = "/dev/shm/argonshutdownflag.txt"
|
||||||
|
|
||||||
|
# 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:
|
||||||
|
try:
|
||||||
|
if os.path.isfile(SHUTDOWN_FLAGFILE):
|
||||||
|
display_defaultimg()
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
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
|
||||||
|
readq.task_done()
|
||||||
|
break
|
||||||
|
elif qdata == "OLEDSTOP":
|
||||||
|
# End OLED Thread
|
||||||
|
display_defaultimg()
|
||||||
|
readq.task_done()
|
||||||
|
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":
|
||||||
|
try:
|
||||||
|
with open(SHUTDOWN_FLAGFILE, "w") as f:
|
||||||
|
f.write("signalled")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Signal poweroff
|
||||||
|
argonregister_signalpoweroff(bus)
|
||||||
|
|
||||||
|
if OLED_ENABLED == True:
|
||||||
|
display_defaultimg()
|
||||||
|
|
||||||
|
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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
tmpfile="/dev/shm/argontmpconf.txt"
|
||||||
|
daemonconfigfile="/etc/argononeupd.conf"
|
||||||
|
|
||||||
|
if [ -f "$daemonconfigfile" ]
|
||||||
|
then
|
||||||
|
. $daemonconfigfile
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$lidshutdownsecs" ]
|
||||||
|
then
|
||||||
|
lidshutdownsecs=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
mainloopflag=1
|
||||||
|
newmode=0
|
||||||
|
|
||||||
|
|
||||||
|
get_number () {
|
||||||
|
read curnumber
|
||||||
|
if [ -z "$curnumber" ]
|
||||||
|
then
|
||||||
|
echo "-2"
|
||||||
|
return
|
||||||
|
elif [[ $curnumber =~ ^[+-]?[0-9]+$ ]]
|
||||||
|
then
|
||||||
|
if [ $curnumber -lt 0 ]
|
||||||
|
then
|
||||||
|
echo "-1"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo $curnumber
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
echo "-1"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
while [ $mainloopflag -eq 1 ]
|
||||||
|
do
|
||||||
|
|
||||||
|
lidshutdownmins=$((lidshutdownsecs / 60))
|
||||||
|
|
||||||
|
|
||||||
|
echo "------------------------------------------"
|
||||||
|
echo " Argon One Up Lid Configuration Tool"
|
||||||
|
echo "------------------------------------------"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "Lid Close Behavior:"
|
||||||
|
if [ $lidshutdownsecs -lt 1 ]
|
||||||
|
then
|
||||||
|
echo "(Do Nothing)"
|
||||||
|
else
|
||||||
|
echo "(Shut down after $lidshutdownmins minute(s))"
|
||||||
|
fi
|
||||||
|
echo " 1. Do Nothing"
|
||||||
|
echo " 2. Shutdown"
|
||||||
|
echo
|
||||||
|
echo " 0. Exit"
|
||||||
|
echo "NOTE: You can also edit $daemonconfigfile directly"
|
||||||
|
echo -n "Enter Number (0-2):"
|
||||||
|
newmode=$( get_number )
|
||||||
|
|
||||||
|
if [[ $newmode -eq 0 ]]
|
||||||
|
then
|
||||||
|
mainloopflag=0
|
||||||
|
elif [ $newmode -eq 1 ]
|
||||||
|
then
|
||||||
|
lidshutdownsecs=0
|
||||||
|
elif [ $newmode -eq 2 ]
|
||||||
|
then
|
||||||
|
maxmins=120
|
||||||
|
echo "Please provide number of minutes until shutdown:"
|
||||||
|
echo -n "Enter Number (1-$maxmins):"
|
||||||
|
curval=$( get_number )
|
||||||
|
if [ $curval -gt $maxmins ]
|
||||||
|
then
|
||||||
|
newmode=0
|
||||||
|
echo "Invalid input"
|
||||||
|
elif [ $curval -lt 1 ]
|
||||||
|
then
|
||||||
|
newmode=0
|
||||||
|
echo "Invalid input"
|
||||||
|
else
|
||||||
|
lidshutdownsecs=$((curval * 60))
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $newmode -eq 1 ] || [ $newmode -eq 2 ]
|
||||||
|
then
|
||||||
|
if [ -f "$daemonconfigfile" ]
|
||||||
|
then
|
||||||
|
grep -v 'lidshutdownsecs' "$daemonconfigfile" > $tmpfile
|
||||||
|
else
|
||||||
|
echo '#' > $tmpfile
|
||||||
|
echo '# Argon One Up Configuration' >> $tmpfile
|
||||||
|
echo '#' >> $tmpfile
|
||||||
|
fi
|
||||||
|
echo '# lidshutdownsecs number of seconds till shutdown when lid is closed 0 if do nothing' >> $tmpfile
|
||||||
|
echo "lidshutdownsecs=$lidshutdownsecs" >> $tmpfile
|
||||||
|
|
||||||
|
sudo cp $tmpfile $daemonconfigfile
|
||||||
|
sudo chmod 666 $daemonconfigfile
|
||||||
|
|
||||||
|
echo "Configuration updated."
|
||||||
|
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
@@ -0,0 +1,474 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
#
|
||||||
|
# This script monitor battery via ic2 and keyboard events.
|
||||||
|
#
|
||||||
|
# Additional comments are found in each function below
|
||||||
|
#
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
from threading import Thread
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
sys.path.append("/etc/argon/")
|
||||||
|
from argonregister import *
|
||||||
|
from argonpowerbutton import *
|
||||||
|
|
||||||
|
# Initialize I2C Bus
|
||||||
|
bus = argonregister_initializebusobj()
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
ADDR_BATTERY = 0x64
|
||||||
|
|
||||||
|
UPS_LOGFILE="/dev/shm/upslog.txt"
|
||||||
|
|
||||||
|
|
||||||
|
###################
|
||||||
|
# Utilty Functions
|
||||||
|
###################
|
||||||
|
|
||||||
|
# Debug Logger
|
||||||
|
def debuglog(typestr, logstr):
|
||||||
|
try:
|
||||||
|
DEBUGFILE="/dev/shm/argononeupdebuglog.txt"
|
||||||
|
tmpstrpadding = " "
|
||||||
|
|
||||||
|
with open(DEBUGFILE, "a") as txt_file:
|
||||||
|
txt_file.write("["+time.asctime(time.localtime(time.time()))+"] "+typestr.upper()+" "+logstr.strip().replace("\n","\n"+tmpstrpadding)+"\n")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# System Notifcation
|
||||||
|
def notifymessage(message, iscritical):
|
||||||
|
if not isinstance(message, str) or len(message.strip()) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
wftype="notify"
|
||||||
|
if iscritical:
|
||||||
|
wftype="critical"
|
||||||
|
os.system("export SUDO_UID=1000; wfpanelctl "+wftype+" \""+message+"\"")
|
||||||
|
os.system("export DISPLAY=:0.0; lxpanelctl notify \""+message+"\"")
|
||||||
|
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Battery
|
||||||
|
#############
|
||||||
|
REG_CONTROL = 0x08
|
||||||
|
REG_SOCALERT = 0x0b
|
||||||
|
REG_PROFILE = 0x10
|
||||||
|
REG_ICSTATE = 0xA7
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def battery_restart():
|
||||||
|
# Set to active mode
|
||||||
|
try:
|
||||||
|
maxretry = 3
|
||||||
|
while maxretry > 0:
|
||||||
|
maxretry = maxretry - 1
|
||||||
|
|
||||||
|
# Restart
|
||||||
|
bus.write_byte_data(ADDR_BATTERY, REG_CONTROL, 0x30)
|
||||||
|
time.sleep(0.5)
|
||||||
|
# Activate
|
||||||
|
bus.write_byte_data(ADDR_BATTERY, REG_CONTROL, 0x00)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
# Wait for Ready Status
|
||||||
|
maxwaitsecs = 5
|
||||||
|
while maxwaitsecs > 0:
|
||||||
|
tmpval = bus.read_byte_data(ADDR_BATTERY, REG_ICSTATE)
|
||||||
|
if (tmpval&0x0C) != 0:
|
||||||
|
debuglog("battery-activate", "Activated Successfully")
|
||||||
|
return 0
|
||||||
|
time.sleep(1)
|
||||||
|
maxwaitsecs = maxwaitsecs - 1
|
||||||
|
|
||||||
|
|
||||||
|
debuglog("battery-activate", "Failed to activate")
|
||||||
|
return 2
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
debuglog("battery-activateerror", str(e))
|
||||||
|
except:
|
||||||
|
debuglog("battery-activateerror", "Activation Failed")
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def battery_getstatus(restartifnotactive):
|
||||||
|
try:
|
||||||
|
tmpval = bus.read_byte_data(ADDR_BATTERY, REG_CONTROL)
|
||||||
|
if tmpval != 0:
|
||||||
|
if restartifnotactive == True:
|
||||||
|
tmpval = battery_restart()
|
||||||
|
|
||||||
|
if tmpval != 0:
|
||||||
|
debuglog("battery-status", "Inactive "+str(tmpval))
|
||||||
|
return 2
|
||||||
|
|
||||||
|
tmpval = bus.read_byte_data(ADDR_BATTERY, REG_SOCALERT)
|
||||||
|
if (tmpval&0x80) == 0:
|
||||||
|
debuglog("battery-status", "Profile not ready "+str(tmpval))
|
||||||
|
return 3
|
||||||
|
|
||||||
|
# OK
|
||||||
|
#debuglog("battery-status", "OK")
|
||||||
|
return 0
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
debuglog("battery-status-error", str(e))
|
||||||
|
except:
|
||||||
|
debuglog("battery-status-error", "Battery Status Failed")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def battery_checkupdateprofile():
|
||||||
|
try:
|
||||||
|
REG_GPIOCONFIG = 0x0A
|
||||||
|
|
||||||
|
PROFILE_DATALIST = [0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xA8,0xAA,0xBE,0xC6,0xB8,0xAE,0xC2,0x98,0x82,0xFF,0xFF,0xCA,0x98,0x75,0x63,0x55,0x4E,0x4C,0x49,0x98,0x88,0xDC,0x34,0xDB,0xD3,0xD4,0xD3,0xD0,0xCE,0xCB,0xBB,0xE7,0xA2,0xC2,0xC4,0xAE,0x96,0x89,0x80,0x74,0x67,0x63,0x71,0x8E,0x9F,0x85,0x6F,0x3B,0x20,0x00,0xAB,0x10,0xFF,0xB0,0x73,0x00,0x00,0x00,0x64,0x08,0xD3,0x77,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFA]
|
||||||
|
|
||||||
|
PROFILE_LEN = len(PROFILE_DATALIST)
|
||||||
|
|
||||||
|
# Try to compare profile if battery is active
|
||||||
|
tmpidx = 0
|
||||||
|
|
||||||
|
tmpval = battery_getstatus(True)
|
||||||
|
if tmpval == 0:
|
||||||
|
# Status OK, check profile
|
||||||
|
tmpidx = 0
|
||||||
|
while tmpidx < PROFILE_LEN:
|
||||||
|
tmpval = bus.read_byte_data(ADDR_BATTERY, REG_PROFILE+tmpidx)
|
||||||
|
if tmpval != PROFILE_DATALIST[tmpidx]:
|
||||||
|
debuglog("battery-profile-error", "Mismatch")
|
||||||
|
break
|
||||||
|
tmpidx = tmpidx + 1
|
||||||
|
|
||||||
|
if tmpidx == PROFILE_LEN:
|
||||||
|
# Matched
|
||||||
|
return 0
|
||||||
|
else:
|
||||||
|
debuglog("battery-profile", "Status Error "+str(tmpval)+", will attempt to update")
|
||||||
|
|
||||||
|
# needs update
|
||||||
|
debuglog("battery-profile", "Updating...")
|
||||||
|
|
||||||
|
# Device Sleep state
|
||||||
|
|
||||||
|
# Restart
|
||||||
|
bus.write_byte_data(ADDR_BATTERY, REG_CONTROL, 0x30)
|
||||||
|
time.sleep(0.5)
|
||||||
|
# Sleep
|
||||||
|
bus.write_byte_data(ADDR_BATTERY, REG_CONTROL, 0xF0)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
# Write Profile
|
||||||
|
tmpidx = 0
|
||||||
|
while tmpidx < PROFILE_LEN:
|
||||||
|
bus.write_byte_data(ADDR_BATTERY, REG_PROFILE+tmpidx, PROFILE_DATALIST[tmpidx])
|
||||||
|
tmpidx = tmpidx + 1
|
||||||
|
|
||||||
|
debuglog("battery-profile", "Profile Updated,Restarting...")
|
||||||
|
|
||||||
|
# Set Update Flag
|
||||||
|
bus.write_byte_data(ADDR_BATTERY, REG_SOCALERT, 0x80)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
# Close Interrupts
|
||||||
|
bus.write_byte_data(ADDR_BATTERY, REG_GPIOCONFIG, 0)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
# Restart Battery
|
||||||
|
tmpval = battery_restart()
|
||||||
|
if tmpval == 0:
|
||||||
|
debuglog("battery-profile", "Update Completed")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
debuglog("battery-profile", "Unable to restart")
|
||||||
|
return 3
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
debuglog("battery-profile-error", str(e))
|
||||||
|
except:
|
||||||
|
debuglog("battery-profile-error", "Battery Profile Check/Update Failed")
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def battery_getpercent():
|
||||||
|
# State of Charge (SOC)
|
||||||
|
try:
|
||||||
|
SOC_HIGH_REG = 0x04
|
||||||
|
|
||||||
|
socpercent = bus.read_byte_data(ADDR_BATTERY, SOC_HIGH_REG)
|
||||||
|
if socpercent > 100:
|
||||||
|
return 100
|
||||||
|
elif socpercent > 0:
|
||||||
|
return socpercent
|
||||||
|
|
||||||
|
# Support Fraction percent
|
||||||
|
#SOC_LOW_REG = 0x05
|
||||||
|
#soc_low = bus.read_byte_data(ADDR_BATTERY, SOC_LOW_REG)
|
||||||
|
#socpercentfloat = socpercent + (soc_low / 256.0)
|
||||||
|
#if socpercentfloat > 100.0:
|
||||||
|
# return 100.0
|
||||||
|
#elif socpercentfloat > 0.0:
|
||||||
|
# return socpercentfloat
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
debuglog("battery-percenterror", str(e))
|
||||||
|
except:
|
||||||
|
debuglog("battery-percenterror", "Read Battery Failed")
|
||||||
|
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
def battery_isplugged():
|
||||||
|
# State of Charge (SOC)
|
||||||
|
try:
|
||||||
|
CURRENT_HIGH_REG = 0x0E
|
||||||
|
|
||||||
|
current_high = bus.read_byte_data(ADDR_BATTERY, CURRENT_HIGH_REG)
|
||||||
|
|
||||||
|
if (current_high & 0x80) > 0:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
#CURRENT_LOW_REG = 0x0F
|
||||||
|
#R_SENSE = 10.0
|
||||||
|
#current_low = bus.read_byte_data(ADDR_BATTERY, CURRENT_LOW_REG)
|
||||||
|
#raw_current = int.from_bytes([current_high, current_low], byteorder='big', signed=True)
|
||||||
|
#current = (52.4 * raw_current) / (32768 * R_SENSE)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
debuglog("battery-chargingerror", str(e))
|
||||||
|
except:
|
||||||
|
debuglog("battery-chargingerror", "Read Charging Failed")
|
||||||
|
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def battery_loadlogdata():
|
||||||
|
# status, version, time, schedule
|
||||||
|
outobj = {}
|
||||||
|
try:
|
||||||
|
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
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return outobj
|
||||||
|
|
||||||
|
def battery_check(readq):
|
||||||
|
CMDSTARTBYTE=0xfe
|
||||||
|
CMDCONTROLBYTECOUNT=3
|
||||||
|
CHECKSTATUSLOOPFREQ=50
|
||||||
|
|
||||||
|
CMDsendrequest = [ 0xfe, 0, 0, 0xfe, 0xfe, 0, 0, 0xfe, 0, 0, 0]
|
||||||
|
|
||||||
|
lastcmdtime=""
|
||||||
|
loopCtr = CHECKSTATUSLOOPFREQ
|
||||||
|
sendcmdid = -1
|
||||||
|
|
||||||
|
debuglog("battery", "Starting")
|
||||||
|
|
||||||
|
updatedesktopicon("Argon ONE UP", "/etc/argon/argon40.png")
|
||||||
|
|
||||||
|
maxretry = 5
|
||||||
|
while maxretry > 0:
|
||||||
|
try:
|
||||||
|
if battery_checkupdateprofile() == 0:
|
||||||
|
break
|
||||||
|
except Exception as mainerr:
|
||||||
|
try:
|
||||||
|
debuglog("battery-mainerror", str(mainerr))
|
||||||
|
except:
|
||||||
|
debuglog("battery-mainerror", "Error")
|
||||||
|
# Give time before retry
|
||||||
|
time.sleep(10)
|
||||||
|
maxretry = maxretry - 1
|
||||||
|
|
||||||
|
while maxretry > 0: # Outer loop; maxretry never decrements so infinite
|
||||||
|
qdata = ""
|
||||||
|
if readq.empty() == False:
|
||||||
|
qdata = readq.get()
|
||||||
|
|
||||||
|
if battery_getstatus(True) != 0:
|
||||||
|
# Give time before retry
|
||||||
|
time.sleep(3)
|
||||||
|
continue
|
||||||
|
|
||||||
|
prevnotifymsg = ""
|
||||||
|
previconfile = ""
|
||||||
|
statusstr = ""
|
||||||
|
|
||||||
|
shutdowntriggered=False
|
||||||
|
needsupdate=False
|
||||||
|
device_battery=0
|
||||||
|
device_charging=0
|
||||||
|
|
||||||
|
while True: # Command loop
|
||||||
|
try:
|
||||||
|
if sendcmdid < 0:
|
||||||
|
cmddatastr = ""
|
||||||
|
|
||||||
|
if cmddatastr == "":
|
||||||
|
if loopCtr >= CHECKSTATUSLOOPFREQ:
|
||||||
|
# Check Battery Status
|
||||||
|
sendcmdid = 0
|
||||||
|
loopCtr = 0
|
||||||
|
else:
|
||||||
|
loopCtr = loopCtr + 1
|
||||||
|
if (loopCtr&1) == 0:
|
||||||
|
sendcmdid = 0 # Check Battery Status
|
||||||
|
|
||||||
|
if sendcmdid == 0:
|
||||||
|
tmp_battery = battery_getpercent()
|
||||||
|
tmp_charging = battery_isplugged()
|
||||||
|
|
||||||
|
if tmp_charging < 0 or tmp_battery < 0:
|
||||||
|
# communication error, retain old value
|
||||||
|
tmp_charging = device_charging
|
||||||
|
tmp_battery = device_battery
|
||||||
|
|
||||||
|
if tmp_charging != device_charging or tmp_battery!=device_battery:
|
||||||
|
device_battery=tmp_battery
|
||||||
|
device_charging=tmp_charging
|
||||||
|
tmpiconfile = "/etc/argon/ups/"
|
||||||
|
needsupdate=True
|
||||||
|
curnotifymsg = ""
|
||||||
|
curnotifycritical = False
|
||||||
|
|
||||||
|
if device_battery>99:
|
||||||
|
# Prevents switching issue
|
||||||
|
statusstr = "Charged"
|
||||||
|
curnotifymsg = statusstr
|
||||||
|
tmpiconfile = tmpiconfile+"charge_"+str(device_battery)
|
||||||
|
elif device_charging == 0:
|
||||||
|
statusstr = "Charging"
|
||||||
|
curnotifymsg = statusstr
|
||||||
|
tmpiconfile = tmpiconfile+"charge_"+str(device_battery)
|
||||||
|
else:
|
||||||
|
statusstr = "Battery"
|
||||||
|
tmpiconfile = tmpiconfile+"discharge_"+str(device_battery)
|
||||||
|
|
||||||
|
if device_battery > 50:
|
||||||
|
curnotifymsg="Battery Mode"
|
||||||
|
elif device_battery > 20:
|
||||||
|
curnotifymsg="50%% Battery"
|
||||||
|
elif device_battery > 10:
|
||||||
|
curnotifymsg="20%% Battery"
|
||||||
|
elif device_battery > 5:
|
||||||
|
#curnotifymsg="Low Battery"
|
||||||
|
curnotifymsg="Low Battery: The device may power off automatically soon."
|
||||||
|
curnotifycritical=True
|
||||||
|
else:
|
||||||
|
curnotifymsg="CRITICAL BATTERY: Shutting Down in 1 minute"
|
||||||
|
curnotifycritical=True
|
||||||
|
|
||||||
|
tmpiconfile = tmpiconfile + ".png"
|
||||||
|
statusstr = statusstr + " " + str(device_battery)+"%"
|
||||||
|
|
||||||
|
# Add/update desktop icons too; add check to minimize write
|
||||||
|
if previconfile != tmpiconfile:
|
||||||
|
updatedesktopicon(statusstr, tmpiconfile)
|
||||||
|
previconfile = tmpiconfile
|
||||||
|
|
||||||
|
# Send notification if necessary
|
||||||
|
if prevnotifymsg != curnotifymsg:
|
||||||
|
notifymessage(curnotifymsg, curnotifycritical)
|
||||||
|
if shutdowntriggered==False and device_battery <= 5 and device_charging != 0:
|
||||||
|
shutdowntriggered=True
|
||||||
|
os.system("shutdown +1 """+curnotifymsg+".""")
|
||||||
|
debuglog("battery-shutdown", "Shutdown in 1 minute")
|
||||||
|
|
||||||
|
if shutdowntriggered==True and (device_charging == 0 or device_battery>=10):
|
||||||
|
shutdowntriggered=False
|
||||||
|
os.system("shutdown -c ""Charging, shutdown cancelled.""")
|
||||||
|
debuglog("battery-shutdown", "Abort")
|
||||||
|
|
||||||
|
prevnotifymsg = curnotifymsg
|
||||||
|
|
||||||
|
|
||||||
|
sendcmdid=-1
|
||||||
|
|
||||||
|
if needsupdate==True:
|
||||||
|
# Log File
|
||||||
|
otherstr = ""
|
||||||
|
with open(UPS_LOGFILE, "w") as txt_file:
|
||||||
|
txt_file.write("Status as of: "+time.asctime(time.localtime(time.time()))+"\n Power:"+statusstr+"\n"+otherstr)
|
||||||
|
|
||||||
|
needsupdate=False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
debuglog("battery-error", str(e))
|
||||||
|
except:
|
||||||
|
debuglog("battery-error", "Error")
|
||||||
|
break
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
def updatedesktopicon(statusstr, tmpiconfile):
|
||||||
|
try:
|
||||||
|
icontitle = "Argon ONE UP"
|
||||||
|
tmp = os.popen("find /home -maxdepth 1 -type d").read()
|
||||||
|
alllines = tmp.split("\n")
|
||||||
|
for curfolder in alllines:
|
||||||
|
if curfolder == "/home" or curfolder == "":
|
||||||
|
continue
|
||||||
|
#debuglog("desktop-update-path", curfolder)
|
||||||
|
#debuglog("desktop-update-text", statusstr)
|
||||||
|
#debuglog("desktop-update-icon", tmpiconfile)
|
||||||
|
with open(curfolder+"/Desktop/argononeup.desktop", "w") as txt_file:
|
||||||
|
txt_file.write("[Desktop Entry]\nName="+icontitle+"\nComment="+statusstr+"\nIcon="+tmpiconfile+"\nExec=lxterminal --working-directory="+curfolder+"/ -t \"Argon ONE UP\" -e \"/etc/argon/argon-config\"\nType=Application\nEncoding=UTF-8\nTerminal=false\nCategories=None;\n")
|
||||||
|
except Exception as desktope:
|
||||||
|
#pass
|
||||||
|
try:
|
||||||
|
debuglog("desktop-update-error", str(desktope))
|
||||||
|
except:
|
||||||
|
debuglog("desktop-update-error", "Error")
|
||||||
|
|
||||||
|
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
cmd = sys.argv[1].upper()
|
||||||
|
if cmd == "GETBATTERY":
|
||||||
|
outobj = battery_loadlogdata()
|
||||||
|
try:
|
||||||
|
print(outobj["power"])
|
||||||
|
except:
|
||||||
|
print("Error retrieving battery status")
|
||||||
|
elif cmd == "RESETBATTERY":
|
||||||
|
battery_checkupdateprofile()
|
||||||
|
|
||||||
|
elif cmd == "SERVICE":
|
||||||
|
# Starts sudo level services
|
||||||
|
try:
|
||||||
|
ipcq = Queue()
|
||||||
|
if len(sys.argv) > 2:
|
||||||
|
cmd = sys.argv[2].upper()
|
||||||
|
t1 = Thread(target = battery_check, args =(ipcq, ))
|
||||||
|
t2 = Thread(target = argonpowerbutton_monitorlid, args =(ipcq, ))
|
||||||
|
|
||||||
|
t1.start()
|
||||||
|
t2.start()
|
||||||
|
|
||||||
|
ipcq.join()
|
||||||
|
except Exception:
|
||||||
|
sys.exit(1)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Argon ONE UP Service
|
||||||
|
After=multi-user.target
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RemainAfterExit=true
|
||||||
|
ExecStart=/usr/bin/python3 /etc/argon/argononeupd.py SERVICE
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Argon ONE UP Service
|
||||||
|
After=multi-user.target
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RemainAfterExit=true
|
||||||
|
ExecStart=/usr/bin/python3 /etc/argon/argonkeyboard.py SERVICE
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
UPS_LOGFILE="/dev/shm/upslog.txt"
|
||||||
|
#UPS_DEVFILE="/dev/argonbatteryicon"
|
||||||
|
|
||||||
|
def notifymessage(message, iscritical):
|
||||||
|
wftype="notify"
|
||||||
|
if iscritical:
|
||||||
|
wftype="critical"
|
||||||
|
os.system("export SUDO_UID=1000; wfpanelctl "+wftype+" \""+message+"\"")
|
||||||
|
os.system("export DISPLAY=:0.0; lxpanelctl notify \""+message+"\"")
|
||||||
|
|
||||||
|
try:
|
||||||
|
outobj = {}
|
||||||
|
#os.system("insmod /etc/argon/ups/argonbatteryicon.ko")
|
||||||
|
prevnotifymsg=""
|
||||||
|
|
||||||
|
tmp_battery = 100
|
||||||
|
tmp_charging = 1
|
||||||
|
|
||||||
|
device_battery = -1
|
||||||
|
device_charging = -1
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
# 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("%",""))
|
||||||
|
except:
|
||||||
|
tmp_charging = device_charging
|
||||||
|
tmp_battery = device_battery
|
||||||
|
|
||||||
|
# Update module data if changed
|
||||||
|
if tmp_charging != device_charging or tmp_battery!=device_battery:
|
||||||
|
device_charging = tmp_charging
|
||||||
|
device_battery = tmp_battery
|
||||||
|
|
||||||
|
# No longer using default battery indicator
|
||||||
|
#try:
|
||||||
|
# with open(UPS_DEVFILE, 'w') as f:
|
||||||
|
# f.write("capacity = "+str(device_battery)+"\ncharging = "+str(device_charging)+"\n")
|
||||||
|
#except Exception as e:
|
||||||
|
# pass
|
||||||
|
|
||||||
|
curnotifymsg = ""
|
||||||
|
curnotifycritical=False
|
||||||
|
|
||||||
|
if tmp_charging:
|
||||||
|
if "Shutting Down" in prevnotifymsg:
|
||||||
|
os.system("shutdown -c ""Charging, shutdown cancelled.""")
|
||||||
|
|
||||||
|
if tmp_battery > 99:
|
||||||
|
curnotifymsg="Fully Charged"
|
||||||
|
elif tmp_charging:
|
||||||
|
curnotifymsg="Charging"
|
||||||
|
else:
|
||||||
|
if tmp_battery > 50:
|
||||||
|
curnotifymsg="Battery Mode"
|
||||||
|
elif tmp_battery > 20:
|
||||||
|
curnotifymsg="50%% Battery"
|
||||||
|
elif tmp_battery > 10:
|
||||||
|
curnotifymsg="20%% Battery"
|
||||||
|
elif tmp_battery > 5:
|
||||||
|
#curnotifymsg="Low Battery"
|
||||||
|
curnotifymsg="Low Battery: The device may power off automatically soon."
|
||||||
|
curnotifycritical=True
|
||||||
|
else:
|
||||||
|
curnotifymsg="CRITICAL BATTERY: Shutting Down in 1 minute"
|
||||||
|
curnotifycritical=True
|
||||||
|
|
||||||
|
|
||||||
|
if prevnotifymsg != curnotifymsg:
|
||||||
|
notifymessage(curnotifymsg, curnotifycritical)
|
||||||
|
if tmp_battery <= 5 and tmp_charging == 0:
|
||||||
|
os.system("shutdown +1 """+curnotifymsg+".""")
|
||||||
|
|
||||||
|
prevnotifymsg = curnotifymsg
|
||||||
|
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
time.sleep(60)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Argon Industria UPS Battery Service
|
||||||
|
DefaultDependencies=no
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=sysinit.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
KillSignal=SIGINT
|
||||||
|
TimeoutStopSec=8
|
||||||
|
Restart=on-failure
|
||||||
|
WorkingDirectory=/etc/argon/ups/
|
||||||
|
ExecStart=/usr/bin/python3 /etc/argon/argononeupsd.py
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Debug Logger
|
||||||
|
def argonpowerbutton_debuglog(typestr, logstr):
|
||||||
|
try:
|
||||||
|
DEBUGFILE="/dev/shm/argononegpiodebuglog.txt"
|
||||||
|
tmpstrpadding = " "
|
||||||
|
|
||||||
|
with open(DEBUGFILE, "a") as txt_file:
|
||||||
|
txt_file.write("["+time.asctime(time.localtime(time.time()))+"] "+typestr.upper()+" "+logstr.strip().replace("\n","\n"+tmpstrpadding)+"\n")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def argonpowerbutton_getvalue(lineobj,lineid):
|
||||||
|
if lineid is not None:
|
||||||
|
tmpval = lineobj.get_value(lineid) != gpiod.line.Value.INACTIVE
|
||||||
|
if tmpval == False:
|
||||||
|
return 0
|
||||||
|
return 1
|
||||||
|
return lineobj.get_value()
|
||||||
|
|
||||||
|
def argonpowerbutton_watchline(debugname, dataq, lineid, callback):
|
||||||
|
monitormode = True
|
||||||
|
argonpowerbutton_debuglog(debugname, "Starting")
|
||||||
|
# Pi5 mapping, 0 for older
|
||||||
|
chippath = '/dev/gpiochip4'
|
||||||
|
try:
|
||||||
|
chip = gpiod.Chip(chippath)
|
||||||
|
except Exception as gpioerr:
|
||||||
|
try:
|
||||||
|
# Old mapping
|
||||||
|
chippath = '/dev/gpiochip0'
|
||||||
|
chip = gpiod.Chip(chippath)
|
||||||
|
except Exception as gpioolderr:
|
||||||
|
chippath = ""
|
||||||
|
|
||||||
|
if len(chippath) == 0:
|
||||||
|
argonpowerbutton_debuglog(debugname+"-error", "Unable to initialize GPIO")
|
||||||
|
try:
|
||||||
|
dataq.put("ERROR")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
# Monitoring starts
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
# Reference https://github.com/brgl/libgpiod/blob/master/bindings/python/examples/gpiomon.py
|
||||||
|
|
||||||
|
lineobj = chip.get_line(lineid)
|
||||||
|
if lineid == 27:
|
||||||
|
lineobj.request(consumer="argon", type=gpiod.LINE_REQ_EV_BOTH_EDGES, flags=gpiod.LINE_REQ_FLAG_BIAS_PULL_UP)
|
||||||
|
else:
|
||||||
|
lineobj.request(consumer="argon", type=gpiod.LINE_REQ_EV_BOTH_EDGES)
|
||||||
|
while monitormode == True:
|
||||||
|
hasevent = lineobj.event_wait(10)
|
||||||
|
if hasevent:
|
||||||
|
eventdata = lineobj.event_read()
|
||||||
|
monitormode = callback(eventdata.type == gpiod.LineEvent.RISING_EDGE, lineobj, dataq, None)
|
||||||
|
|
||||||
|
lineobj.release()
|
||||||
|
chip.close()
|
||||||
|
except Exception:
|
||||||
|
# https://github.com/brgl/libgpiod/blob/master/bindings/python/examples/watch_line_rising.py
|
||||||
|
configobj = {lineid: gpiod.LineSettings(direction=gpiod.line.Direction.INPUT, edge_detection=gpiod.line.Edge.BOTH)}
|
||||||
|
if lineid == 27:
|
||||||
|
configobj = {lineid: gpiod.LineSettings(direction=gpiod.line.Direction.INPUT, edge_detection=gpiod.line.Edge.BOTH, bias=gpiod.line.Bias.PULL_UP )}
|
||||||
|
|
||||||
|
with gpiod.request_lines(
|
||||||
|
chippath,
|
||||||
|
consumer="argon",
|
||||||
|
config=configobj,
|
||||||
|
) as request:
|
||||||
|
while monitormode:
|
||||||
|
# Blocks until at least one event is available
|
||||||
|
for event in request.read_edge_events():
|
||||||
|
monitormode = callback(event.event_type == event.Type.RISING_EDGE, request, dataq, event.line_offset)
|
||||||
|
except Exception as monitorerror:
|
||||||
|
try:
|
||||||
|
argonpowerbutton_debuglog(debugname+"-error", str(monitorerror))
|
||||||
|
except:
|
||||||
|
argonpowerbutton_debuglog(debugname+"-error", "Error aborting")
|
||||||
|
try:
|
||||||
|
dataq.put("ERROR")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 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_getconfigval(keyname, datatype="int"):
|
||||||
|
keyname = keyname.lower()
|
||||||
|
fname = "/etc/argononeupd.conf"
|
||||||
|
try:
|
||||||
|
with open(fname, "r") as fp:
|
||||||
|
for curline in fp:
|
||||||
|
if not curline:
|
||||||
|
continue
|
||||||
|
tmpline = curline.replace(" ", "").replace("\t", "")
|
||||||
|
if not tmpline:
|
||||||
|
continue
|
||||||
|
if tmpline[0] == "#":
|
||||||
|
continue
|
||||||
|
tmppair = tmpline.split("=")
|
||||||
|
if len(tmppair) != 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
tmpvar = tmppair[0].lower()
|
||||||
|
if tmpvar != keyname:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
if datatype == "int":
|
||||||
|
return int(tmppair[1])
|
||||||
|
elif datatype == "float":
|
||||||
|
return float(tmppair[1])
|
||||||
|
return tmppair[1]
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if datatype == "int":
|
||||||
|
return -1
|
||||||
|
elif datatype == "float":
|
||||||
|
return -1
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def argonpowerbutton_monitorlidevent(isrising, lineobj, writeq, lineid):
|
||||||
|
if isrising == False:
|
||||||
|
targetsecs = argonpowerbutton_getconfigval("lidshutdownsecs")
|
||||||
|
if targetsecs > 0:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Close Detect; Wait for :"+str(targetsecs))
|
||||||
|
else:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Close Detected; Do nothing")
|
||||||
|
# Time pulse data
|
||||||
|
time.sleep(1)
|
||||||
|
pulsetimesec = 1
|
||||||
|
# 0 - Lid is closed, 1 - Lid is open
|
||||||
|
while argonpowerbutton_getvalue(lineobj, lineid) == 0:
|
||||||
|
if targetsecs > 0:
|
||||||
|
if pulsetimesec >= targetsecs:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Target Reached, shutting down")
|
||||||
|
monitormode = False
|
||||||
|
os.system("shutdown now -h")
|
||||||
|
return False
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
pulsetimesec += 1
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Open Detected")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def argonpowerbutton_monitorlid(writeq):
|
||||||
|
LINE_LIDMONITOR=27
|
||||||
|
argonpowerbutton_watchline("lid-monitor", writeq, LINE_LIDMONITOR, argonpowerbutton_monitorlidevent)
|
||||||
|
|
||||||
|
def argonpowerbutton_monitorevent(isrising, lineobj, writeq, lineid):
|
||||||
|
pulsetime = 0
|
||||||
|
if isrising == True:
|
||||||
|
# Time pulse data
|
||||||
|
while argonpowerbutton_getvalue(lineobj, lineid) == 1:
|
||||||
|
time.sleep(0.01)
|
||||||
|
pulsetime += 1
|
||||||
|
|
||||||
|
if pulsetime >=2 and pulsetime <=3:
|
||||||
|
# Testing
|
||||||
|
#writeq.put("OLEDSWITCH")
|
||||||
|
writeq.put("OLEDSTOP")
|
||||||
|
os.system("reboot")
|
||||||
|
return False
|
||||||
|
elif pulsetime >=4 and pulsetime <=5:
|
||||||
|
writeq.put("OLEDSTOP")
|
||||||
|
os.system("shutdown now -h")
|
||||||
|
return False
|
||||||
|
elif pulsetime >=6 and pulsetime <=7:
|
||||||
|
writeq.put("OLEDSWITCH")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def argonpowerbutton_monitor(writeq):
|
||||||
|
LINE_SHUTDOWN=4
|
||||||
|
argonpowerbutton_watchline("button", writeq, LINE_SHUTDOWN, argonpowerbutton_monitorevent)
|
||||||
|
|
||||||
|
|
||||||
|
def argonpowerbutton_monitorswitchevent(isrising, lineobj, writeq, lineid):
|
||||||
|
pulsetime = 0
|
||||||
|
if isrising == True:
|
||||||
|
# Time pulse data
|
||||||
|
while argonpowerbutton_getvalue(lineobj, lineid) == 1:
|
||||||
|
time.sleep(0.01)
|
||||||
|
pulsetime += 1
|
||||||
|
|
||||||
|
if pulsetime >= 10:
|
||||||
|
writeq.put("OLEDSWITCH")
|
||||||
|
return True
|
||||||
|
|
||||||
|
def argonpowerbutton_monitorswitch(writeq):
|
||||||
|
LINE_SHUTDOWN=4
|
||||||
|
argonpowerbutton_watchline("button-switch", writeq, LINE_SHUTDOWN, argonpowerbutton_monitorswitchevent)
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
#argonpowerbutton_monitor(None)
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Debug Logger
|
||||||
|
def argonpowerbutton_debuglog(typestr, logstr):
|
||||||
|
try:
|
||||||
|
DEBUGFILE="/dev/shm/argononegpiodebuglog.txt"
|
||||||
|
tmpstrpadding = " "
|
||||||
|
|
||||||
|
with open(DEBUGFILE, "a") as txt_file:
|
||||||
|
txt_file.write("["+time.asctime(time.localtime(time.time()))+"] "+typestr.upper()+" "+logstr.strip().replace("\n","\n"+tmpstrpadding)+"\n")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# 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_getconfigval(keyname, datatype="int"):
|
||||||
|
keyname = keyname.lower()
|
||||||
|
fname = "/etc/argononeupd.conf"
|
||||||
|
try:
|
||||||
|
with open(fname, "r") as fp:
|
||||||
|
for curline in fp:
|
||||||
|
if not curline:
|
||||||
|
continue
|
||||||
|
tmpline = curline.replace(" ", "").replace("\t", "")
|
||||||
|
if not tmpline:
|
||||||
|
continue
|
||||||
|
if tmpline[0] == "#":
|
||||||
|
continue
|
||||||
|
tmppair = tmpline.split("=")
|
||||||
|
if len(tmppair) != 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
tmpvar = tmppair[0].lower()
|
||||||
|
if tmpvar != keyname:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
if datatype == "int":
|
||||||
|
return int(tmppair[1])
|
||||||
|
elif datatype == "float":
|
||||||
|
return float(tmppair[1])
|
||||||
|
return tmppair[1]
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if datatype == "int":
|
||||||
|
return -1
|
||||||
|
elif datatype == "float":
|
||||||
|
return -1
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def argonpowerbutton_monitorlid(writeq):
|
||||||
|
try:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Starting")
|
||||||
|
monitormode = True
|
||||||
|
# 0 - Lid is closed, 1 - Lid is open
|
||||||
|
# Pin Assignments
|
||||||
|
PIN_LIDMONITOR=27
|
||||||
|
|
||||||
|
GPIO.setwarnings(False)
|
||||||
|
GPIO.setmode(GPIO.BCM)
|
||||||
|
GPIO.setup(PIN_LIDMONITOR, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
||||||
|
|
||||||
|
while monitormode == True:
|
||||||
|
pulsetimesec = 1
|
||||||
|
GPIO.wait_for_edge(PIN_LIDMONITOR, GPIO.FALLING)
|
||||||
|
targetsecs = argonpowerbutton_getconfigval("lidshutdownsecs")
|
||||||
|
if targetsecs > 0:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Close Detect; Wait for :"+str(targetsecs))
|
||||||
|
else:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Close Detected; Do nothing")
|
||||||
|
# Time pulse data
|
||||||
|
time.sleep(1)
|
||||||
|
while GPIO.input(PIN_LIDMONITOR) == GPIO.LOW:
|
||||||
|
if targetsecs > 0:
|
||||||
|
if pulsetimesec >= targetsecs:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Target Reached, shutting down")
|
||||||
|
monitormode = False
|
||||||
|
os.system("shutdown now -h")
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
pulsetimesec += 1
|
||||||
|
argonpowerbutton_debuglog("lid-monitor", "Open Detected")
|
||||||
|
except Exception as liderror:
|
||||||
|
try:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor-error", str(liderror))
|
||||||
|
except:
|
||||||
|
argonpowerbutton_debuglog("lid-monitor-error", "Error aborting")
|
||||||
|
#pass
|
||||||
|
GPIO.cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
||||||
@@ -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)
|
||||||
@@ -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)
|
||||||
@@ -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]
|
||||||
|
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
@@ -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}
|
||||||
@@ -0,0 +1,564 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
import math
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import serial
|
||||||
|
|
||||||
|
from threading import Thread
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
sys.path.append("/etc/argon/")
|
||||||
|
import argonrtc
|
||||||
|
|
||||||
|
|
||||||
|
#################
|
||||||
|
# Common/Helpers
|
||||||
|
#################
|
||||||
|
#UPS_SERIALPORT="/dev/ttyUSB0"
|
||||||
|
UPS_SERIALPORT="/dev/ttyACM0"
|
||||||
|
UPS_LOGFILE="/dev/shm/upslog.txt"
|
||||||
|
UPS_CMDFILE="/dev/shm/upscmd.txt"
|
||||||
|
|
||||||
|
RTC_CONFIGFILE = "/etc/argonupsrtc.conf"
|
||||||
|
|
||||||
|
|
||||||
|
#############
|
||||||
|
# RTC
|
||||||
|
#############
|
||||||
|
|
||||||
|
def hexAsDec(hexval):
|
||||||
|
return (hexval&0xF) + 10*((hexval>>4)&0xf)
|
||||||
|
|
||||||
|
def decAsHex(decval):
|
||||||
|
return (decval%10) + (math.floor(decval/10)<<4)
|
||||||
|
|
||||||
|
# Returns RTC timestamp as datetime object
|
||||||
|
def getDatetimeObj(dataobj, datakey):
|
||||||
|
try:
|
||||||
|
datetimearray = dataobj[datakey].split(" ")
|
||||||
|
if len(datetimearray)>1:
|
||||||
|
datearray = datetimearray[0].split("/")
|
||||||
|
timearray = datetimearray[1].split(":")
|
||||||
|
if len(datearray) == 3 and len(timearray) > 1:
|
||||||
|
year = int(datearray[2])
|
||||||
|
month = int(datearray[0])
|
||||||
|
caldate = int(datearray[1])
|
||||||
|
hour = int(timearray[0])
|
||||||
|
minute = int(timearray[1])
|
||||||
|
second = 0
|
||||||
|
if len(timearray) > 2:
|
||||||
|
second = int(timearray[2])
|
||||||
|
return datetime.datetime(year, month, caldate, hour, minute, second)+argonrtc.getLocaltimeOffset()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return datetime.datetime(1999, 1, 1, 0, 0, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def getRTCpoweronschedule():
|
||||||
|
outobj = ups_sendcmd("7")
|
||||||
|
return getDatetimeObj(outobj, "schedule")
|
||||||
|
|
||||||
|
|
||||||
|
def getRTCdatetime():
|
||||||
|
outobj = ups_sendcmd("5")
|
||||||
|
return getDatetimeObj(outobj, "time")
|
||||||
|
|
||||||
|
|
||||||
|
# set RTC time using datetime object (Local time)
|
||||||
|
def setRTCdatetime():
|
||||||
|
# Set local time to UTC
|
||||||
|
outobj = ups_sendcmd("3")
|
||||||
|
return getDatetimeObj(outobj, "time")
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
return nextcommandtime
|
||||||
|
|
||||||
|
# Convert to RTC timezone
|
||||||
|
alarmtime = nextcommandtime - argonrtc.getLocaltimeOffset()
|
||||||
|
|
||||||
|
outobj = ups_sendcmd("6 "+alarmtime.strftime("%Y %m %d %H %M"))
|
||||||
|
return getDatetimeObj(outobj, "schedule")
|
||||||
|
|
||||||
|
|
||||||
|
#############
|
||||||
|
# Status
|
||||||
|
#############
|
||||||
|
|
||||||
|
def ups_debuglog(typestr, logstr):
|
||||||
|
try:
|
||||||
|
UPS_DEBUGFILE="/dev/shm/upsdebuglog.txt"
|
||||||
|
|
||||||
|
tmpstrpadding = " "
|
||||||
|
|
||||||
|
with open(UPS_DEBUGFILE, "a") as txt_file:
|
||||||
|
txt_file.write("["+datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+"] "+typestr.upper()+" "+logstr.strip().replace("\n","\n"+tmpstrpadding)+"\n")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def ups_sendcmd(cmdstr):
|
||||||
|
# status, version, time, schedule
|
||||||
|
ups_debuglog("sendcmd", cmdstr)
|
||||||
|
try:
|
||||||
|
outstr = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
||||||
|
|
||||||
|
with open(UPS_CMDFILE, "w") as txt_file:
|
||||||
|
txt_file.write(datetime.datetime.now().strftime("%Y%m%d%H%M%S")+"\n"+cmdstr+"\n")
|
||||||
|
time.sleep(3)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
outobj = ups_loadlogdata()
|
||||||
|
try:
|
||||||
|
ups_debuglog("sendcmd-response", json.dumps(outobj))
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return outobj
|
||||||
|
|
||||||
|
def ups_loadlogdata():
|
||||||
|
# status, version, time, schedule
|
||||||
|
outobj = {}
|
||||||
|
try:
|
||||||
|
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
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return outobj
|
||||||
|
|
||||||
|
def ups_check(readq):
|
||||||
|
CMDSTARTBYTE=0xfe
|
||||||
|
CMDCONTROLBYTECOUNT=3
|
||||||
|
CHECKSTATUSLOOPFREQ=50
|
||||||
|
|
||||||
|
CMDsendrequest = [ 0xfe, 0, 0, 0xfe, 0xfe, 0, 0, 0xfe, 0, 0, 0]
|
||||||
|
|
||||||
|
lastcmdtime=""
|
||||||
|
loopCtr = CHECKSTATUSLOOPFREQ
|
||||||
|
sendcmdid = -1
|
||||||
|
|
||||||
|
ups_debuglog("serial", "Starting "+UPS_SERIALPORT)
|
||||||
|
|
||||||
|
updatedesktopicon("Argon UPS", "Argon UPS", "/etc/argon/ups/loading_0.png")
|
||||||
|
|
||||||
|
while True: # Outer loop to reconnect to device
|
||||||
|
|
||||||
|
qdata = ""
|
||||||
|
if readq.empty() == False:
|
||||||
|
qdata = readq.get()
|
||||||
|
|
||||||
|
try:
|
||||||
|
ser = serial.Serial(UPS_SERIALPORT, 115200, timeout = 1)
|
||||||
|
ser.close()
|
||||||
|
ser.open()
|
||||||
|
except Exception as mainerr:
|
||||||
|
try:
|
||||||
|
ups_debuglog("serial-mainerror", str(mainerr))
|
||||||
|
except:
|
||||||
|
ups_debuglog("serial-mainerror", "Error")
|
||||||
|
# Give time before retry
|
||||||
|
time.sleep(10)
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
previconfile = ""
|
||||||
|
statusstr = ""
|
||||||
|
device_battery=0
|
||||||
|
device_charging=0
|
||||||
|
device_chargecurrent=-1
|
||||||
|
device_version=-1
|
||||||
|
device_rtctime= [-1, -1, -1, -1, -1, -1]
|
||||||
|
device_powerontime= [-1, -1, -1, -1, -1]
|
||||||
|
|
||||||
|
while True: # Command loop
|
||||||
|
try:
|
||||||
|
if sendcmdid < 0:
|
||||||
|
cmddatastr = ""
|
||||||
|
try:
|
||||||
|
fp = open(UPS_CMDFILE, "r")
|
||||||
|
cmdlog = fp.read()
|
||||||
|
alllines = cmdlog.split("\n")
|
||||||
|
if len(alllines) > 1:
|
||||||
|
if lastcmdtime != alllines[0]:
|
||||||
|
lastcmdtime=alllines[0]
|
||||||
|
cmddatastr=alllines[1]
|
||||||
|
tmpcmdarray = cmddatastr.split(" ")
|
||||||
|
sendcmdid = int(tmpcmdarray[0])
|
||||||
|
if sendcmdid == 3:
|
||||||
|
# Get/rebuild time here to minimize delay/time gap
|
||||||
|
newrtcdatetime = datetime.datetime.now() - argonrtc.getLocaltimeOffset()
|
||||||
|
cmddatastr = ("3 "+newrtcdatetime.strftime("%Y %m %d %H %M %S"))
|
||||||
|
tmpcmdarray = cmddatastr.split(" ")
|
||||||
|
if len(tmpcmdarray) != 7:
|
||||||
|
cmddatastr = ""
|
||||||
|
sendcmdid = 0
|
||||||
|
elif sendcmdid == 6:
|
||||||
|
if len(tmpcmdarray) != 6:
|
||||||
|
cmddatastr = ""
|
||||||
|
sendcmdid = 0
|
||||||
|
except OSError:
|
||||||
|
cmddatastr = ""
|
||||||
|
|
||||||
|
if cmddatastr == "":
|
||||||
|
if loopCtr >= CHECKSTATUSLOOPFREQ:
|
||||||
|
# Check Battery Status
|
||||||
|
sendcmdid = 0
|
||||||
|
loopCtr = 0
|
||||||
|
else:
|
||||||
|
loopCtr = loopCtr + 1
|
||||||
|
if loopCtr == 2:
|
||||||
|
sendcmdid = 5 # Get RTC Time
|
||||||
|
elif loopCtr == 3:
|
||||||
|
sendcmdid = 7 # Get Power on Time
|
||||||
|
elif loopCtr == 4:
|
||||||
|
sendcmdid = 4 # Get Version
|
||||||
|
elif loopCtr == 5:
|
||||||
|
sendcmdid = 2 # Get Charge Current
|
||||||
|
elif (loopCtr&1) == 0:
|
||||||
|
sendcmdid = 0 # Check Battery Status
|
||||||
|
|
||||||
|
if sendcmdid >= 0:
|
||||||
|
sendSize = 0
|
||||||
|
cmdSize = 0
|
||||||
|
if len(cmddatastr) > 0:
|
||||||
|
# set RTC Time (3, 6 bytes)
|
||||||
|
# set Power of Time (6, 5 bytes)
|
||||||
|
tmpcmdarray = cmddatastr.split(" ")
|
||||||
|
CMDsendrequest[1] = len(tmpcmdarray) - 1 # Length
|
||||||
|
CMDsendrequest[2] = sendcmdid
|
||||||
|
|
||||||
|
cmdSize = CMDsendrequest[1] + 4
|
||||||
|
|
||||||
|
# Copy payload
|
||||||
|
tmpdataidx = cmdSize - 1 # Start at end
|
||||||
|
while tmpdataidx > 3:
|
||||||
|
tmpdataidx = tmpdataidx - 1
|
||||||
|
if tmpdataidx == 3 and (sendcmdid == 3 or sendcmdid == 6):
|
||||||
|
tmpval = int(tmpcmdarray[tmpdataidx-2])
|
||||||
|
if tmpval >= 2000:
|
||||||
|
tmpval = tmpval - 2000
|
||||||
|
else:
|
||||||
|
tmpval = 0
|
||||||
|
CMDsendrequest[tmpdataidx] = decAsHex(tmpval)
|
||||||
|
else:
|
||||||
|
CMDsendrequest[tmpdataidx] = decAsHex(int(tmpcmdarray[tmpdataidx-2]))
|
||||||
|
|
||||||
|
datasum = 0
|
||||||
|
tmpdataidx = cmdSize - 1
|
||||||
|
while tmpdataidx > 0:
|
||||||
|
tmpdataidx = tmpdataidx - 1
|
||||||
|
datasum = (datasum+CMDsendrequest[tmpdataidx]) & 0xff
|
||||||
|
|
||||||
|
CMDsendrequest[cmdSize-1] = datasum
|
||||||
|
sendSize = ser.write(serial.to_bytes(CMDsendrequest[0:cmdSize]))
|
||||||
|
|
||||||
|
ups_debuglog("serial-out-cmd", serial.to_bytes(CMDsendrequest[0:cmdSize]).hex(" "))
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Default Get/Read command
|
||||||
|
CMDsendrequest[1] = 0 # Length
|
||||||
|
CMDsendrequest[2] = sendcmdid
|
||||||
|
CMDsendrequest[3] = (sendcmdid+CMDsendrequest[0]) & 0xff
|
||||||
|
sendSize = ser.write(serial.to_bytes(CMDsendrequest[0:4]))
|
||||||
|
cmdSize = CMDsendrequest[1] + 4
|
||||||
|
|
||||||
|
#ups_debuglog("serial-out-def", serial.to_bytes(CMDsendrequest[0:4]).hex(" "))
|
||||||
|
|
||||||
|
if cmdSize > 0:
|
||||||
|
sendcmdid=-1
|
||||||
|
if sendSize == cmdSize:
|
||||||
|
# Give time to respond
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# read incoming data
|
||||||
|
readOut = ser.read()
|
||||||
|
|
||||||
|
if len(readOut) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
readdatalen = 1
|
||||||
|
while True:
|
||||||
|
tmpreadlen = ser.inWaiting() # Check remaining byte size
|
||||||
|
if tmpreadlen < 1:
|
||||||
|
break
|
||||||
|
readOut += ser.read(tmpreadlen)
|
||||||
|
readdatalen += tmpreadlen
|
||||||
|
|
||||||
|
readintarray = [tmpint for tmpint in readOut]
|
||||||
|
|
||||||
|
if len(cmddatastr) > 0:
|
||||||
|
ups_debuglog("serial-in ", readOut.hex(" "))
|
||||||
|
cmddatastr = ""
|
||||||
|
# Parse command stream
|
||||||
|
tmpidx = 0
|
||||||
|
while tmpidx < readdatalen:
|
||||||
|
if readintarray[tmpidx] == CMDSTARTBYTE and tmpidx + CMDCONTROLBYTECOUNT < readdatalen:
|
||||||
|
# Cmd format: Min 4 bytes
|
||||||
|
# tmpidx tmpidx+1 tmpidx+2
|
||||||
|
# 0xfe (byte count) (cmd ID) (payload; byte count) (datasum)
|
||||||
|
|
||||||
|
tmpdatalen = readintarray[tmpidx+1]
|
||||||
|
tmpcmd = readintarray[tmpidx+2]
|
||||||
|
if tmpidx + CMDCONTROLBYTECOUNT + tmpdatalen < readdatalen:
|
||||||
|
# Validate datasum
|
||||||
|
datasum = 0
|
||||||
|
tmpdataidx = tmpidx + tmpdatalen + CMDCONTROLBYTECOUNT
|
||||||
|
while tmpdataidx > tmpidx:
|
||||||
|
tmpdataidx = tmpdataidx - 1
|
||||||
|
datasum = (datasum+readintarray[tmpdataidx]) & 0xff
|
||||||
|
if datasum != readintarray[tmpidx + tmpdatalen + CMDCONTROLBYTECOUNT]:
|
||||||
|
# Invalid sum
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
needsupdate=False
|
||||||
|
if tmpcmd == 0:
|
||||||
|
# Check State
|
||||||
|
if tmpdatalen >= 2:
|
||||||
|
needsupdate=True
|
||||||
|
tmp_battery = readintarray[tmpidx+CMDCONTROLBYTECOUNT]
|
||||||
|
if tmp_battery>100:
|
||||||
|
tmp_battery=100
|
||||||
|
elif tmp_battery<1:
|
||||||
|
tmp_battery=0
|
||||||
|
tmp_charging = readintarray[tmpidx+CMDCONTROLBYTECOUNT+1]
|
||||||
|
#ups_debuglog("battery-data", str(tmp_charging)+" "+str(tmp_battery))
|
||||||
|
|
||||||
|
if tmp_charging != device_charging or tmp_battery!=device_battery:
|
||||||
|
device_battery=tmp_battery
|
||||||
|
device_charging=tmp_charging
|
||||||
|
tmpiconfile = "/etc/argon/ups/"
|
||||||
|
|
||||||
|
icontitle = "Argon UPS"
|
||||||
|
if device_charging == 0:
|
||||||
|
if device_battery==100:
|
||||||
|
statusstr = "Charged"
|
||||||
|
#tmpiconfile = tmpiconfile+"battery_plug"
|
||||||
|
else:
|
||||||
|
#icontitle = str(device_battery)+"%"+" Full"
|
||||||
|
statusstr = "Charging"
|
||||||
|
#tmpiconfile = tmpiconfile+"battery_charging"
|
||||||
|
tmpiconfile = tmpiconfile+"charge_"+str(device_battery)
|
||||||
|
else:
|
||||||
|
#icontitle = str(device_battery)+"%"+" Left"
|
||||||
|
statusstr = "Battery"
|
||||||
|
tmpiconfile = tmpiconfile+"discharge_"+str(device_battery)
|
||||||
|
tmpiconfile = tmpiconfile + ".png"
|
||||||
|
|
||||||
|
statusstr = statusstr + " " + str(device_battery)+"%"
|
||||||
|
|
||||||
|
#ups_debuglog("battery-info", statusstr)
|
||||||
|
|
||||||
|
# Add/update desktop icons too; add check to minimize write
|
||||||
|
if previconfile != tmpiconfile:
|
||||||
|
updatedesktopicon(icontitle, statusstr, tmpiconfile)
|
||||||
|
previconfile = tmpiconfile
|
||||||
|
|
||||||
|
elif tmpcmd == 2:
|
||||||
|
# Charge Current
|
||||||
|
if tmpdatalen >= 2:
|
||||||
|
device_chargecurrent = ((readintarray[tmpidx+CMDCONTROLBYTECOUNT])<<8) | readintarray[tmpidx+CMDCONTROLBYTECOUNT+1]
|
||||||
|
elif tmpcmd == 4:
|
||||||
|
# Version
|
||||||
|
if tmpdatalen >= 1:
|
||||||
|
needsupdate=True
|
||||||
|
device_version = readintarray[tmpidx+CMDCONTROLBYTECOUNT]
|
||||||
|
elif tmpcmd == 5:
|
||||||
|
# RTC Time
|
||||||
|
if tmpdatalen >= 6:
|
||||||
|
needsupdate=True
|
||||||
|
tmpdataidx = 0
|
||||||
|
while tmpdataidx < 6:
|
||||||
|
device_rtctime[tmpdataidx] = hexAsDec(readintarray[tmpidx+CMDCONTROLBYTECOUNT+tmpdataidx])
|
||||||
|
tmpdataidx = tmpdataidx + 1
|
||||||
|
elif tmpcmd == 7:
|
||||||
|
# Power On Time
|
||||||
|
if tmpdatalen >= 5:
|
||||||
|
needsupdate=True
|
||||||
|
tmpdataidx = 0
|
||||||
|
while tmpdataidx < 5:
|
||||||
|
device_powerontime[tmpdataidx] = hexAsDec(readintarray[tmpidx+CMDCONTROLBYTECOUNT+tmpdataidx])
|
||||||
|
tmpdataidx = tmpdataidx + 1
|
||||||
|
elif tmpcmd == 8:
|
||||||
|
# Send Acknowledge
|
||||||
|
sendcmdid = tmpcmd
|
||||||
|
elif tmpcmd == 3:
|
||||||
|
# New RTC Time set
|
||||||
|
sendcmdid = 5
|
||||||
|
elif tmpcmd == 6:
|
||||||
|
# New Power On Time set
|
||||||
|
sendcmdid = 7
|
||||||
|
|
||||||
|
if needsupdate==True:
|
||||||
|
# Log File
|
||||||
|
otherstr = ""
|
||||||
|
if device_version >= 0:
|
||||||
|
otherstr = otherstr + " Version:"+str(device_version)+"\n"
|
||||||
|
if device_rtctime[0] >= 0:
|
||||||
|
otherstr = otherstr + " Time:"+str(device_rtctime[1])+"/"+str(device_rtctime[2])+"/"+str(device_rtctime[0]+2000)+" "+str(device_rtctime[3])+":"+str(device_rtctime[4])+":"+str(device_rtctime[5])+"\n"
|
||||||
|
if device_powerontime[1] > 0:
|
||||||
|
otherstr = otherstr + " Schedule:"+str(device_powerontime[1])+"/"+str(device_powerontime[2])+"/"+str(device_powerontime[0]+2000)+" "+str(device_powerontime[3])+":"+str(device_powerontime[4])+"\n"
|
||||||
|
with open(UPS_LOGFILE, "w") as txt_file:
|
||||||
|
txt_file.write("Status as of: "+time.asctime(time.localtime(time.time()))+"\n Power:"+statusstr+"\n"+otherstr)
|
||||||
|
#ups_debuglog("status-update", "\n Power:"+statusstr+"\n"+otherstr)
|
||||||
|
# Point to datasum, so next loop iteration will be correct
|
||||||
|
tmpidx = tmpidx + tmpdatalen + CMDCONTROLBYTECOUNT
|
||||||
|
tmpidx = tmpidx + 1
|
||||||
|
except Exception as e:
|
||||||
|
try:
|
||||||
|
ups_debuglog("serial-error", str(e))
|
||||||
|
except:
|
||||||
|
ups_debuglog("serial-error", "Error")
|
||||||
|
break
|
||||||
|
|
||||||
|
def updatedesktopicon(icontitle, statusstr, tmpiconfile):
|
||||||
|
try:
|
||||||
|
tmp = os.popen("find /home -maxdepth 1 -type d").read()
|
||||||
|
alllines = tmp.split("\n")
|
||||||
|
for curfolder in alllines:
|
||||||
|
if curfolder == "/home" or curfolder == "":
|
||||||
|
continue
|
||||||
|
#ups_debuglog("desktop-update-path", curfolder)
|
||||||
|
#ups_debuglog("desktop-update-text", statusstr)
|
||||||
|
#ups_debuglog("desktop-update-icon", tmpiconfile)
|
||||||
|
with open(curfolder+"/Desktop/argonone-ups.desktop", "w") as txt_file:
|
||||||
|
txt_file.write("[Desktop Entry]\nName="+icontitle+"\nComment="+statusstr+"\nIcon="+tmpiconfile+"\nExec=lxterminal --working-directory="+curfolder+"/ -t \"Argon UPS\" -e \"/etc/argon/argonone-upsconfig.sh argonupsrtc\"\nType=Application\nEncoding=UTF-8\nTerminal=false\nCategories=None;\n")
|
||||||
|
except Exception as desktope:
|
||||||
|
#pass
|
||||||
|
try:
|
||||||
|
ups_debuglog("desktop-update-error", str(desktope))
|
||||||
|
except:
|
||||||
|
ups_debuglog("desktop-update-error", "Error")
|
||||||
|
|
||||||
|
|
||||||
|
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()
|
||||||
|
if cmd == "GETBATTERY":
|
||||||
|
#outobj = ups_sendcmd("0")
|
||||||
|
outobj = ups_loadlogdata()
|
||||||
|
try:
|
||||||
|
print(outobj["power"])
|
||||||
|
except:
|
||||||
|
print("Error retrieving battery status")
|
||||||
|
|
||||||
|
elif cmd == "GETRTCSCHEDULE":
|
||||||
|
tmptime = getRTCpoweronschedule()
|
||||||
|
if tmptime.year > 1999:
|
||||||
|
print("Alarm Setting:", tmptime)
|
||||||
|
else:
|
||||||
|
print("Alarm Setting: None")
|
||||||
|
|
||||||
|
elif cmd == "GETRTCTIME":
|
||||||
|
tmptime = getRTCdatetime()
|
||||||
|
if tmptime.year > 1999:
|
||||||
|
print("RTC Time:", tmptime)
|
||||||
|
else:
|
||||||
|
print("Error reading RTC Time")
|
||||||
|
|
||||||
|
elif cmd == "UPDATERTCTIME":
|
||||||
|
tmptime = setRTCdatetime()
|
||||||
|
if tmptime.year > 1999:
|
||||||
|
print("RTC Time:", tmptime)
|
||||||
|
else:
|
||||||
|
print("Error reading RTC Time")
|
||||||
|
|
||||||
|
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":
|
||||||
|
ipcq = Queue()
|
||||||
|
|
||||||
|
tmprtctime = getRTCdatetime()
|
||||||
|
if tmprtctime.year >= 2000:
|
||||||
|
argonrtc.updateSystemTime(tmprtctime)
|
||||||
|
commandschedulelist = argonrtc.formCommandScheduleList(argonrtc.loadConfigList(RTC_CONFIGFILE))
|
||||||
|
nextrtcalarmtime = setNextAlarm(commandschedulelist, datetime.datetime.now())
|
||||||
|
|
||||||
|
t1 = Thread(target = ups_check, args =(ipcq, ))
|
||||||
|
t1.start()
|
||||||
|
|
||||||
|
serviceloop = True
|
||||||
|
while serviceloop==True:
|
||||||
|
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)
|
||||||
|
|
||||||
|
ipcq.join()
|
||||||
|
|
||||||
|
|
||||||
|
elif False:
|
||||||
|
print("System Time: ", datetime.datetime.now())
|
||||||
|
print("RTC Time: ", getRTCdatetime())
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Argon UPS RTC Service
|
||||||
|
After=multi-user.target
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
RemainAfterExit=true
|
||||||
|
ExecStart=/usr/bin/python3 /etc/argon/argonupsrtcd.py SERVICE
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -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
|
||||||
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 127 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 161 B |
|
After Width: | Height: | Size: 142 B |
|
After Width: | Height: | Size: 161 B |