Compare commits

...

2 Commits

Author SHA1 Message Date
simon 10ff0bda27 new script energy.py to parce acpi for i3blocks 2021-01-29 17:55:00 +07:00
simon 48cc791e7e some cosmetic improvements from pylint 2021-01-29 10:50:42 +07:00
3 changed files with 181 additions and 12 deletions

View File

@ -41,6 +41,9 @@ A bunch of simple bash scripts to be called via i3blocks.
* **wifiinfo.sh**: Echos current db level of signal strength.
* on left click: Uses nmcli to echo all device status.
## i3block_py
A collection of standalone python scripts for the slightly more complicated things.
* **energy.py**: parses `acpi` to output current battery status. Uses `notify-send` to send messages on changes.
## weather_applet
Standalone script that pulls weather data from [openweathermap.org](https://openweathermap.org/) and prints out

164
i3block_py/energy.py Executable file
View File

@ -0,0 +1,164 @@
#!/usr/bin/env python3
""" parses output of acpi to monitor battery status """
import subprocess
LOG_FILE_PATH = "/tmp/battery_status.log"
def get_acpi():
""" get acpi data as a sting """
acpi_raw = subprocess.run(["acpi"], capture_output=True, check=False)
acpi_string = acpi_raw.stdout.decode().strip()
return acpi_string
def parse_acpi(acpi):
""" split acpi string into its parts """
state_list = acpi.split(': ')[1].split(',')
battery_state_list = [i.strip() for i in state_list]
# catch different states
if len(battery_state_list) == 2:
# fully charged
battery_state, battery_level = battery_state_list
time_remaining = False
elif len(battery_state_list) == 3:
# not fully charged
battery_state, battery_level, time_remaining = battery_state_list
time_remaining = time_remaining.split()[0]
time_remaining = parse_time(time_remaining)
battery_level = battery_level.strip('%')
return battery_state, battery_level, time_remaining
def parse_time(time_remaining):
""" returns minutes remaing from 00:00:00 format if a string
else parses minutes back to hh:mm """
if isinstance(time_remaining, int):
if time_remaining > 60:
hour = int(str(time_remaining / 60).split('.')[0])
minutes = time_remaining - ( hour * 60 )
hour_c = str(hour).zfill(2)
minutes_c = str(minutes).zfill(2)
left = f'{hour_c}:{minutes_c}'
else:
minutes_c = str(time_remaining).zfill(2)
left = f'00:{minutes_c}'
else:
time_list = time_remaining.split(':')
time_list.reverse()
# account for different length of str
total_sec = int()
for i in enumerate(time_list):
position, value = [int(j) for j in i]
sec = value * 60 ** position
total_sec = total_sec + sec
# normalize to minutes
left = int(total_sec / 60)
return left
def get_last_log(battery_state, time_remaining):
""" parse log file and return new average min value """
new_line = f'{battery_state} {time_remaining}'
try:
with open(LOG_FILE_PATH, 'r') as last_log_file:
log_lines = last_log_file.readlines()
except FileNotFoundError:
# no log file on first run
return time_remaining, new_line
# get lines
log_lines_clean = [i.strip() for i in log_lines]
last_10 = [i.split() for i in log_lines_clean]
min_list = [int(i[1]) for i in last_10[-2:]]
min_list.append(time_remaining)
# calc avg
avg_min = int(sum(min_list) / len(min_list))
return avg_min, last_10
def write_log(last_10, battery_state, new_avg_min):
""" update the log file """
state_changed = False
if isinstance(last_10[0], type('str')):
log_list = [battery_state, str(new_avg_min)]
log_string = ' '.join(log_list)
elif last_10[-1][0] == battery_state:
# last state is same as current state
last_10.append([battery_state, str(new_avg_min)])
log_list = last_10[-10:]
log_string = '\n'.join([' '.join(i) for i in log_list])
else:
# state changed replace log file
if battery_state == 'Full':
new_avg_min = 0
log_string = f'{battery_state} {new_avg_min}'
state_changed = True
# write to log file
with open(LOG_FILE_PATH, 'w') as log_file:
log_file.write(log_string + '\n')
return state_changed
def print_status(battery_state, battery_level, avg_min, state_changed):
""" will print three lines for i3blocks """
print_main = ""
print_small = ""
print_color = ""
battery_level_int = int(battery_level)
left = parse_time(avg_min)
if battery_state == 'Discharging':
if battery_level_int <= 20:
icon = ""
print_main = "<span background=\'#E53935\'> $battery_level_int% $left</span>"
print_main = f'<span background=\'#E53935\'>{icon} {battery_level_int}% {left}</span>'
print_color = "#ffffff"
elif 20 < battery_level_int <= 25:
icon = ""
print_main = f'{icon} {battery_level_int}% {left}'
print_color = "#ff0000"
elif 25 < battery_level_int <= 40:
icon = ""
print_main = f'{icon} {battery_level_int}% {left}'
print_color = "#ffff00"
elif 40 < battery_level_int <= 70:
icon = ""
print_main = f'{icon} {battery_level_int}% {left}'
elif 70 < battery_level_int <= 90:
icon = ""
print_main = f'{icon} {battery_level_int}% {left}'
else:
icon = ""
print_main = f'{icon} {battery_level_int}% {left}'
elif battery_state == 'Charging':
icon = ""
print_main = f'{icon} {battery_level_int}% {left}'
print_small = f'{icon} {battery_level_int}%'
if battery_level_int <= 20:
print_color = "#E53935"
else:
print_color = "#ffffff"
else:
# full
icon = ""
print_main = f'{icon} {battery_level_int}%'
print_small = f'{icon}'
if state_changed:
subprocess.call(["notify-send", f'{icon} {battery_state}'])
# print
print(print_main)
print(print_small)
print(print_color)
def main():
""" main to run """
acpi = get_acpi()
battery_state, battery_level, time_remaining = parse_acpi(acpi)
new_avg_min, last_10 = get_last_log(battery_state, time_remaining)
state_changed = write_log(last_10, battery_state, new_avg_min)
print_status(battery_state, battery_level, new_avg_min, state_changed)
if __name__ == '__main__':
main()

View File

@ -1,9 +1,12 @@
#!/usr/bin/env python3
""" queries openweathermap to get weather data """
import os
import sys
import configparser
from time import sleep
import requests
from time import sleep
import configparser
import sys, os
iconlist = {
@ -34,13 +37,13 @@ def get_config(config_path):
config_parser = configparser.ConfigParser()
config_parser.read(config_path)
# return false on error
if config_parser.options('api') != ['openweathermap_api_key', 'lat', 'lon']:
print('config parse error')
return False
else:
if config_parser.options('api') == ['openweathermap_api_key', 'lat', 'lon']:
api_key = config_parser.get('api', 'openweathermap_api_key')
lat = config_parser.get('api', 'lat')
lon = config_parser.get('api', 'lon')
else:
print('config parse error')
return False
return api_key, lat, lon
@ -51,17 +54,17 @@ def get_data(api_key, lat, lon):
# try up to 3 times
for i in range(1, 4):
try:
r = requests.get(url, timeout=5)
response = requests.get(url, timeout=5)
except:
sleep(int(i) * 30)
else:
break
# parse response
json = r.json()
json = response.json()
celsius = round(json['main']['temp'])
celsius_pretty = str(celsius) + "°"
icon_ID = json['weather'][0]['icon']
icon = iconlist.get(icon_ID)
icon_id = json['weather'][0]['icon']
icon = iconlist.get(icon_id)
# return
return celsius_pretty, icon
@ -82,4 +85,3 @@ def main():
# start from here
if __name__ == '__main__':
main()