sane-weather: init
for now, all it does is print the current temperature; no caching
This commit is contained in:
36
pkgs/additional/sane-weather/default.nix
Normal file
36
pkgs/additional/sane-weather/default.nix
Normal file
@@ -0,0 +1,36 @@
|
||||
{ stdenv
|
||||
, glib-networking
|
||||
, gobject-introspection
|
||||
, libgweather
|
||||
, python3
|
||||
, wrapGAppsNoGuiHook
|
||||
}:
|
||||
|
||||
let
|
||||
pyEnv = python3.withPackages (ps: [
|
||||
ps.pygobject3
|
||||
]);
|
||||
in
|
||||
stdenv.mkDerivation {
|
||||
pname = "sane-weather";
|
||||
version = "0.1";
|
||||
src = ./.;
|
||||
|
||||
nativeBuildInputs = [
|
||||
gobject-introspection
|
||||
wrapGAppsNoGuiHook
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
glib-networking
|
||||
libgweather
|
||||
pyEnv
|
||||
];
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p "$out/bin"
|
||||
cp sane-weather "$out/bin"
|
||||
runHook postInstall
|
||||
'';
|
||||
}
|
105
pkgs/additional/sane-weather/sane-weather
Executable file
105
pkgs/additional/sane-weather/sane-weather
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env python3
|
||||
# to get GWeather logging, run with
|
||||
# `G_MESSAGES_DEBUG=GWeather`
|
||||
import argparse
|
||||
import code
|
||||
import gi
|
||||
import logging
|
||||
|
||||
gi.require_version('GWeather', '4.0')
|
||||
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GWeather
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class WeatherSource:
|
||||
def __init__(self):
|
||||
self.info = GWeather.Info()
|
||||
self.info.set_application_id('org.uninsane.sane-weather')
|
||||
self.info.set_contact_info('contact@uninsane.org')
|
||||
self.world = GWeather.Location.get_world()
|
||||
|
||||
def query_loc(self, loc: GWeather.Location) -> None:
|
||||
logger.debug(f"querying: {loc.get_coords()}")
|
||||
self.info.set_location(loc)
|
||||
self.info.update()
|
||||
|
||||
def try_get_celcius(self) -> float | None:
|
||||
valid, temp = self.info.get_value_temp(GWeather.TemperatureUnit.CENTIGRADE)
|
||||
logger.debug(f"try_get_celcius: valid={valid}, temp={temp}")
|
||||
if not valid: temp = None
|
||||
|
||||
return temp
|
||||
|
||||
class QueryOp:
|
||||
def __init__(self, loc: GWeather.Location):
|
||||
self.loc = loc
|
||||
|
||||
class PrintTempOp:
|
||||
pass
|
||||
|
||||
class ExitOp:
|
||||
pass
|
||||
|
||||
class TopLevel:
|
||||
def __init__(self):
|
||||
self._loop = GLib.MainLoop()
|
||||
self.source = WeatherSource()
|
||||
self.work_queue = []
|
||||
|
||||
def enqueue(self, op) -> None:
|
||||
self.work_queue.append(op)
|
||||
|
||||
def run(self) -> None:
|
||||
self.enqueue(ExitOp())
|
||||
GLib.idle_add(self.poll)
|
||||
self._loop.run()
|
||||
|
||||
def poll(self) -> bool:
|
||||
work = self.work_queue[0]
|
||||
if isinstance(work, QueryOp):
|
||||
del self.work_queue[0]
|
||||
self.source.query_loc(work.loc)
|
||||
elif isinstance(work, PrintTempOp):
|
||||
temp = self.source.try_get_celcius()
|
||||
if temp is not None:
|
||||
del self.work_queue[0]
|
||||
print(f"{int(temp)} C")
|
||||
elif isinstance(work, ExitOp):
|
||||
logger.debug("quitting GLib MainLoop")
|
||||
self._loop.quit()
|
||||
else:
|
||||
assert False, f"unknown work: {work}"
|
||||
|
||||
return True # re-queue this idle fn
|
||||
|
||||
|
||||
def main():
|
||||
logging.basicConfig()
|
||||
|
||||
parser = argparse.ArgumentParser(description="acquire weather information for user display")
|
||||
parser.add_argument('--interactive', action='store_true', help='drop into a REPL instead of doing anything, for debugging')
|
||||
parser.add_argument('--verbose', action='store_true', help='enable verbose logging') #< only applies immediately to this app; use `G_MESSAGES_DEBUG=all` for more verbosity
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.verbose:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
|
||||
toplevel = TopLevel()
|
||||
# for now, hardcoded; four-letter station code is that from METAR:
|
||||
# - <https://aviationweather.gov/metar>
|
||||
here = GWeather.Location.find_by_station_code(toplevel.source.world, 'KSEA')
|
||||
|
||||
if args.interactive:
|
||||
code.interact(local=dict(**globals(), **locals()))
|
||||
return
|
||||
|
||||
toplevel.enqueue(QueryOp(here))
|
||||
toplevel.enqueue(PrintTempOp())
|
||||
toplevel.run()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@@ -1,14 +1,19 @@
|
||||
{ pkgs
|
||||
, bash
|
||||
, lib
|
||||
, makeWrapper
|
||||
, python3
|
||||
, stdenv
|
||||
, zsh
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (builtins) attrNames attrValues concatStringsSep foldl' map typeOf;
|
||||
inherit (lib) concatMapAttrs;
|
||||
bash' = bash;
|
||||
pkgs' = pkgs;
|
||||
python3' = python3;
|
||||
zsh' = zsh;
|
||||
# create an attrset of
|
||||
# <name> = expected string in the nix-shell invocation
|
||||
# <value> = package to provide
|
||||
@@ -74,33 +79,33 @@ in rec {
|
||||
);
|
||||
|
||||
# `mkShell` specialization for `nix-shell -i bash` scripts.
|
||||
mkBash = { pname, pkgs ? {}, srcPath ? pname, ...}@attrs:
|
||||
mkBash = { pname, pkgs ? {}, srcPath ? pname, bash ? bash', ...}@attrs:
|
||||
let
|
||||
pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs;
|
||||
pkgsEnv = attrValues pkgsAsAttrs;
|
||||
pkgExprs = attrNames pkgsAsAttrs;
|
||||
in mkShell ({
|
||||
inherit pkgsEnv pkgExprs;
|
||||
interpreter = "${pkgs'.bash}/bin/bash";
|
||||
} // (removeAttrs attrs [ "pkgs" ])
|
||||
interpreter = "${bash}/bin/bash";
|
||||
} // (removeAttrs attrs [ "bash" "pkgs" ])
|
||||
);
|
||||
|
||||
# `mkShell` specialization for `nix-shell -i zsh` scripts.
|
||||
mkZsh = { pname, pkgs ? {}, srcPath ? pname, ...}@attrs:
|
||||
mkZsh = { pname, pkgs ? {}, srcPath ? pname, zsh ? zsh', ...}@attrs:
|
||||
let
|
||||
pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs;
|
||||
pkgsEnv = attrValues pkgsAsAttrs;
|
||||
pkgExprs = attrNames pkgsAsAttrs;
|
||||
in mkShell ({
|
||||
inherit pkgsEnv pkgExprs;
|
||||
interpreter = "${pkgs'.zsh}/bin/zsh";
|
||||
} // (removeAttrs attrs [ "pkgs" ])
|
||||
interpreter = "${zsh}/bin/zsh";
|
||||
} // (removeAttrs attrs [ "pkgs" "zsh" ])
|
||||
);
|
||||
|
||||
# `mkShell` specialization for invocations of `nix-shell -p "python3.withPackages (...)"`
|
||||
# pyPkgs argument is parsed the same as pkgs, except that names are assumed to be relative to `"ps"` if specified in list form.
|
||||
# TODO: rename to `mkPython3` for consistency with e.g. `mkBash`
|
||||
mkPython3Bin = { pname, pkgs ? {}, pyPkgs ? {}, srcPath ? pname, ... }@attrs:
|
||||
mkPython3Bin = { pname, pkgs ? {}, pyPkgs ? {}, srcPath ? pname, python3 ? python3', ... }@attrs:
|
||||
let
|
||||
pyEnv = python3.withPackages (ps: attrValues (
|
||||
pkgsToAttrs "ps." ps pyPkgs
|
||||
@@ -118,6 +123,6 @@ in rec {
|
||||
inherit pkgsEnv pkgExprs;
|
||||
interpreter = pyEnv.interpreter;
|
||||
interpreterName = "python3";
|
||||
} // (removeAttrs attrs [ "pkgs" "pyPkgs" ])
|
||||
} // (removeAttrs attrs [ "pkgs" "pyPkgs" "python3" ])
|
||||
);
|
||||
}
|
||||
|
@@ -51,6 +51,7 @@ let
|
||||
mx-sanebot = callPackage ./additional/mx-sanebot { };
|
||||
rtl8723cs-firmware = callPackage ./additional/rtl8723cs-firmware { };
|
||||
sane-scripts = lib.recurseIntoAttrs (callPackage ./additional/sane-scripts { });
|
||||
sane-weather = callPackage ./additional/sane-weather { };
|
||||
static-nix-shell = callPackage ./additional/static-nix-shell { };
|
||||
sublime-music-mobile = callPackage ./additional/sublime-music-mobile { };
|
||||
sxmo-utils = callPackage ./additional/sxmo-utils { };
|
||||
|
Reference in New Issue
Block a user