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
|
{ pkgs
|
||||||
|
, bash
|
||||||
, lib
|
, lib
|
||||||
, makeWrapper
|
, makeWrapper
|
||||||
, python3
|
, python3
|
||||||
, stdenv
|
, stdenv
|
||||||
|
, zsh
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
inherit (builtins) attrNames attrValues concatStringsSep foldl' map typeOf;
|
inherit (builtins) attrNames attrValues concatStringsSep foldl' map typeOf;
|
||||||
inherit (lib) concatMapAttrs;
|
inherit (lib) concatMapAttrs;
|
||||||
|
bash' = bash;
|
||||||
pkgs' = pkgs;
|
pkgs' = pkgs;
|
||||||
|
python3' = python3;
|
||||||
|
zsh' = zsh;
|
||||||
# create an attrset of
|
# create an attrset of
|
||||||
# <name> = expected string in the nix-shell invocation
|
# <name> = expected string in the nix-shell invocation
|
||||||
# <value> = package to provide
|
# <value> = package to provide
|
||||||
@@ -74,33 +79,33 @@ in rec {
|
|||||||
);
|
);
|
||||||
|
|
||||||
# `mkShell` specialization for `nix-shell -i bash` scripts.
|
# `mkShell` specialization for `nix-shell -i bash` scripts.
|
||||||
mkBash = { pname, pkgs ? {}, srcPath ? pname, ...}@attrs:
|
mkBash = { pname, pkgs ? {}, srcPath ? pname, bash ? bash', ...}@attrs:
|
||||||
let
|
let
|
||||||
pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs;
|
pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs;
|
||||||
pkgsEnv = attrValues pkgsAsAttrs;
|
pkgsEnv = attrValues pkgsAsAttrs;
|
||||||
pkgExprs = attrNames pkgsAsAttrs;
|
pkgExprs = attrNames pkgsAsAttrs;
|
||||||
in mkShell ({
|
in mkShell ({
|
||||||
inherit pkgsEnv pkgExprs;
|
inherit pkgsEnv pkgExprs;
|
||||||
interpreter = "${pkgs'.bash}/bin/bash";
|
interpreter = "${bash}/bin/bash";
|
||||||
} // (removeAttrs attrs [ "pkgs" ])
|
} // (removeAttrs attrs [ "bash" "pkgs" ])
|
||||||
);
|
);
|
||||||
|
|
||||||
# `mkShell` specialization for `nix-shell -i zsh` scripts.
|
# `mkShell` specialization for `nix-shell -i zsh` scripts.
|
||||||
mkZsh = { pname, pkgs ? {}, srcPath ? pname, ...}@attrs:
|
mkZsh = { pname, pkgs ? {}, srcPath ? pname, zsh ? zsh', ...}@attrs:
|
||||||
let
|
let
|
||||||
pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs;
|
pkgsAsAttrs = pkgsToAttrs "" pkgs' pkgs;
|
||||||
pkgsEnv = attrValues pkgsAsAttrs;
|
pkgsEnv = attrValues pkgsAsAttrs;
|
||||||
pkgExprs = attrNames pkgsAsAttrs;
|
pkgExprs = attrNames pkgsAsAttrs;
|
||||||
in mkShell ({
|
in mkShell ({
|
||||||
inherit pkgsEnv pkgExprs;
|
inherit pkgsEnv pkgExprs;
|
||||||
interpreter = "${pkgs'.zsh}/bin/zsh";
|
interpreter = "${zsh}/bin/zsh";
|
||||||
} // (removeAttrs attrs [ "pkgs" ])
|
} // (removeAttrs attrs [ "pkgs" "zsh" ])
|
||||||
);
|
);
|
||||||
|
|
||||||
# `mkShell` specialization for invocations of `nix-shell -p "python3.withPackages (...)"`
|
# `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.
|
# 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`
|
# 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
|
let
|
||||||
pyEnv = python3.withPackages (ps: attrValues (
|
pyEnv = python3.withPackages (ps: attrValues (
|
||||||
pkgsToAttrs "ps." ps pyPkgs
|
pkgsToAttrs "ps." ps pyPkgs
|
||||||
@@ -118,6 +123,6 @@ in rec {
|
|||||||
inherit pkgsEnv pkgExprs;
|
inherit pkgsEnv pkgExprs;
|
||||||
interpreter = pyEnv.interpreter;
|
interpreter = pyEnv.interpreter;
|
||||||
interpreterName = "python3";
|
interpreterName = "python3";
|
||||||
} // (removeAttrs attrs [ "pkgs" "pyPkgs" ])
|
} // (removeAttrs attrs [ "pkgs" "pyPkgs" "python3" ])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -51,6 +51,7 @@ let
|
|||||||
mx-sanebot = callPackage ./additional/mx-sanebot { };
|
mx-sanebot = callPackage ./additional/mx-sanebot { };
|
||||||
rtl8723cs-firmware = callPackage ./additional/rtl8723cs-firmware { };
|
rtl8723cs-firmware = callPackage ./additional/rtl8723cs-firmware { };
|
||||||
sane-scripts = lib.recurseIntoAttrs (callPackage ./additional/sane-scripts { });
|
sane-scripts = lib.recurseIntoAttrs (callPackage ./additional/sane-scripts { });
|
||||||
|
sane-weather = callPackage ./additional/sane-weather { };
|
||||||
static-nix-shell = callPackage ./additional/static-nix-shell { };
|
static-nix-shell = callPackage ./additional/static-nix-shell { };
|
||||||
sublime-music-mobile = callPackage ./additional/sublime-music-mobile { };
|
sublime-music-mobile = callPackage ./additional/sublime-music-mobile { };
|
||||||
sxmo-utils = callPackage ./additional/sxmo-utils { };
|
sxmo-utils = callPackage ./additional/sxmo-utils { };
|
||||||
|
Reference in New Issue
Block a user