Weil ich es sonst wieder mühsam zusammengooglen muss:
git config --global user.email "me@mydomain.com"
git config --global user.name "Me"
git config --global http.sslCAInfo Path_to_CA_CRT_file
Weil ich es sonst wieder mühsam zusammengooglen muss:
git config --global user.email "me@mydomain.com"
git config --global user.name "Me"
git config --global http.sslCAInfo Path_to_CA_CRT_file
Es gibt zwar Entities für % der verbleibenden Ladung und die maximale Kapazität aber wie viele kWh die % dann wirklich sind muss man sich selber ausrechnen.
Auch gibt es am Inverter ein Setting für die eiserne Reserve (unter Energy Management/Battery Management wenn als Customer angemeldet), die sollte man natürlich abziehen:
configuration.yaml erweitern:
template:
- sensor:
- name: "Battery Power Remaining"
unit_of_measurement: kWh
device_class: energy
state: >
{% set maximum = states('sensor.byd_battery_box_premium_hv_maximum_capacity') | float %}
{% set charge = states('sensor.byd_battery_box_premium_hv_state_of_charge') | float %}
{{ '%0.2f' % ( ((maximum / 100) * (charge-7) / 1000) if (charge-7) > 0 else 0) }}
Home Assistant wie üblich restarten und schon kann man ein Tile daraus machen:
Wollte mit einem Zigbee Taster (aka “Smart Button”) von Innr (RC210) einen Zigbee Stromzwischenstecker schalten.
Problem 1: Das Ding hat kein State Entity für “gedrückt” bzw. “nicht gedrückt”.
Problem 2: Einmal drücken heißt “Ein”, nochmal drücken heißt “Aus”.
Problem 3 (wenn man neu ist): Das wird mit Home Assistant Events abgewickelt.
Lösung:
Home Assistant / Developer / Events – im unteren Teil “Listen to events” als Subscriptionquelle “zha_event” angeben und start listening benutzen – dann Taster drücken und der Event wird im Feld darunter eingefügt:
Aus dem Teil unter “data” kann man dann einen Trigger für eine Automation basteln:
Als Typ für den Trigger “manual event” angeben, als “Event type” den Text “zha_event” und unter “Event data” die Daten die wir im Developer Modus ermittelt haben (nur device_ieee, unique_id, device_id und das command – hier gerade off/on umgekehrt, einfach ignorieren 😀 )
Wenn man Problem 2 umgehen will und einfach jeder Tastendruck was bewirken soll einfach zwei Trigger in der gleichen Automatisierung – einmal mit “on” und einmal mit “off”.
Wollte Mail von einem Linux VPS schicken aber keinen lokalen MTA installieren (Debian) – mail/mailx aus bsd-mailx und mailutils scheinen das nicht zu können (oder ich bin zu blöd und diverse Dokus die das damit beschreiben auch), s-nail aus dem gleichlautenden Paket kanns aber:
echo "Body" | s-nail -Sv15-compat -Smta=smtp://user:pass@smtp.domain.at:Port -Ssmtp-use-starttls -Ssmtp-auth=login -s "Subject" -r "from@domain.at" -a Attachment.txt "to@domain.at"
User und Passwort müssen URL-Encoded sein.
Energy Flow Card Plus und Power Flow Card Plus können nur 2 bzw. 4 Individualverbraucher anzeigen – man hat normalerweise aber eher mehr Verbraucher die Daten anliefern.
Man könnte jetzt natürlich in die Tiefen von Typescript absteigen und die 2 Cards erweitern oder man macht Gruppen von Verbrauchern und stellt diese dann dar.
Ich habe 2 gemacht damit Power und Energy ident bleiben können – bei Interesse kann ich mir bei der Power Flow Card noch 2 dazu darstellen; die Details zum Verbrauch findet man ja auch in ansprechenderer Form im Energydashboard.
Hab in Unterhaltungselektronik (PC, TVs, Konsolen, Router, Server, etc.) und Haushaltsgeräte (Kühlschränke, Tiefkühler, Waschmaschine, Geschirrspüler, etc.) unterschieden. Für jede der Kategorien braucht man zwei sensor-Templates.
Power-Template:
template:
- sensor:
- name: "Power Electronics Power"
unit_of_measurement: "W"
state: >
{% set pc1 = states('sensor.zigbee_pc1_power') | float %}
{% set pc2 = states('sensor.zigbee_pc2_power') | float %}
{% set tv = states('sensor.zigbee_tv_power') | float %}
{{ (pc1 + pc2 + tv) | round(1, default=0) }}
Energy-Template (wichtig ist state_class: total_increasing sonst passiert in der Card genau nix):
template:
- sensor:
- name: "Power Electronics Summation delivered"
state_class: total_increasing
unit_of_measurement: kWh
device_class: energy
state: >
{% set pc1 = states('sensor.zigbee_pc1_summation_delivered') | float %}
{% set pc2 = states('sensor.zigbee_pc2_summation_delivered') | float %}
{% set tv = states('sensor.zigbee_tv_summation_delivered') | float %}
{{ (pc1 + pc2 + tv) | float }}
Stand vor der Herausforderung im Loginscript die Etikettengrößen für alle verbundenen Drucker neu zu setzen damit spätere Überraschungen weil Printservice das gerne verstellt/vergisst hintangehalten werden.
$c=@'
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;
using Microsoft.Win32;
public class PrinterSettings
{
[DllImport("kernel32.dll", EntryPoint = "GetLastError", SetLastError = false, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern Int32 GetLastError();
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint="DocumentPropertiesA", SetLastError=true, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
private static extern int DocumentProperties(IntPtr hwnd, IntPtr hPrinter, [MarshalAs(UnmanagedType.LPStr)] string pDeviceName, IntPtr pDevModeOutput, ref IntPtr pDevModeInput, int fMode);
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
private static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr PrinterDefaults);
[DllImport("winspool.drv", CharSet = CharSet.Ansi, SetLastError = true)]
private static extern bool SetPrinter(IntPtr hPrinter, int Level, IntPtr pPrinter, int Command);
[StructLayout(LayoutKind.Sequential)]
public struct PRINTER_INFO_9
{
public IntPtr pDevMode;
}
private const short CCDEVICENAME = 32;
private const short CCFORMNAME = 32;
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCDEVICENAME)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public short dmOrientation;
public short dmPaperSize;
public short dmPaperLength;
public short dmPaperWidth;
public short dmScale;
public short dmCopies;
public short dmDefaultSource;
public short dmPrintQuality;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCFORMNAME)]
public string dmFormName;
public short dmUnusedPadding;
public short dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
}
private const int PRINTER_ACCESS_USE = 0x8;
private const int DM_OUT_BUFFER = 0x2;
private const int DM_MODIFY = 0x8;
private const int DM_PAPERSIZE = 0x2;
public static bool ChangePaperSize(string sPrinterName, short nSize)
{
DEVMODE oDM;
IntPtr pNativeDM = IntPtr.Zero;
int nBytesNeeded = 0;
IntPtr hPrinter = new System.IntPtr();
PRINTER_INFO_9 oPrinterInfo;
IntPtr pNativePrinterInfo = IntPtr.Zero;
IntPtr pDummy=IntPtr.Zero;
if (!OpenPrinter(sPrinterName, out hPrinter, IntPtr.Zero))
{
Console.WriteLine("OpenPrinter() failed with error "+Marshal.GetLastWin32Error()+", aborting.");
return false;
}
nBytesNeeded=DocumentProperties(IntPtr.Zero,hPrinter,sPrinterName,IntPtr.Zero,ref pDummy,0);
pNativeDM=Marshal.AllocHGlobal(nBytesNeeded);
DocumentProperties(IntPtr.Zero,hPrinter,sPrinterName,pNativeDM,ref pDummy,DM_OUT_BUFFER);
oDM = (DEVMODE)Marshal.PtrToStructure(pNativeDM, typeof(DEVMODE));
Marshal.FreeHGlobal(pNativeDM);
oDM.dmPaperSize = nSize;
oDM.dmFields |= DM_PAPERSIZE;
pNativeDM = Marshal.AllocHGlobal(Marshal.SizeOf(oDM));
Marshal.StructureToPtr(oDM, pNativeDM, true);
DocumentProperties(IntPtr.Zero,hPrinter,sPrinterName,pNativeDM,ref pDummy,DM_MODIFY);
oPrinterInfo.pDevMode = pNativeDM;
pNativePrinterInfo = Marshal.AllocHGlobal(Marshal.SizeOf(oPrinterInfo));
Marshal.StructureToPtr(oPrinterInfo, pNativePrinterInfo, true);
if (!SetPrinter(hPrinter, 9, pNativePrinterInfo, 0))
{
Console.WriteLine("SetPrinter() failed with error "+Marshal.GetLastWin32Error()+", aborting.");
Cleanup(pNativeDM, pNativePrinterInfo, hPrinter);
return false;
}
Cleanup(pNativeDM, pNativePrinterInfo, hPrinter);
return true;
}
public static void Cleanup(IntPtr pNativeDM,IntPtr pNativePrinterInfo,IntPtr hPrinter)
{
try
{
Console.WriteLine("Memory and handle cleanup");
if (hPrinter != IntPtr.Zero) ClosePrinter(hPrinter);
if (pNativeDM != IntPtr.Zero) Marshal.FreeHGlobal(pNativeDM);
if (pNativePrinterInfo != IntPtr.Zero) Marshal.FreeHGlobal(pNativePrinterInfo);
}
catch (Exception)
{
}
}
}
'@
Add-Type -TypeDefinition $c -ReferencedAssemblies System.Runtime.InteropServices,System.ComponentModel
Add-Type -AssemblyName System.Drawing
$printer="\\meinprintserver\meinverbundenerdrucker"
$ps=New-Object System.Drawing.Printing.PrinterSettings
$ps.PrinterName=$printer
$size=$ps.PaperSizes|? PaperName -like "*meine Etiketten*"
[PrinterSettings]::ChangePaperSize($printer,$size.RawKind)
Größtenteils von hier geklaut und vereinfacht/bereinigt – mit minimalem Fehlerhandling: https://www.codeproject.com/Articles/6899/Changing-printer-settings-using-C
Hatte einen Raspberry 3 übrig und einen Inverter ans LAN zu bringen…und das bitte headless.
Mit Raspberry Pi Imager Raspberry Pi OS Lite (64-bit, Bookworm) MicroSD erzeugen – da kann man WLAN, SSH & Co. schön vorkonfigurieren.
Wenn das Ding dann am WLAN online ist über NetworkManager dieses auf eth0 sharen (nur IPv4)
sudo nmcli con add con-name share-wlan type ethernet ifname eth0 ipv4.method shared ipv6.method ignore
Das macht aus eth0 einen Router/DHCP/DNS Server (mit dnsmasq) mit der Adresse 10.42.0.1/24
Was sich am LAN Interface so tut (wenn man MAC Adresse zwecks Fixierung wissen will)
sudo journalctl -u NetworkManager -f
DHCP Leases findet man in
sudo cat /var/lib/NetworkManager/dnsmasq-eth0.leases
Und statisch kann man sie dann hier definieren:
sudo micro /etc/NetworkManager/dnsmasq-shared.d/static-addresses
1 Host pro Zeile:
dhcp-host=mm:mm:mm:mm:mm:mm,10.42.0.xxx
Quelle: https://fedoramagazine.org/internet-connection-sharing-networkmanager/
Nur für ZBDongle-E – also der mit EFR32MG21 (Silicon Labs) Chip, nicht der mit CC2652p (Texas Instruments)!!
Am besten alles als root durchführen (oder als Normaluser bis zum pip install und danach das source/flashing als root) da naturgemäß der Normaluser nicht direkt aufs Device schreiben darf.
Python virtual environment erzeugen und aktivieren (activate.fish für Fish Shell), Flasher installieren
python -m venv ./universal-silabs-flasher
source ./universal-silabs-flasher/bin/activate
pip install universal-silabs-flasher
Firmware runterladen (das .gbl File)
https://github.com/itead/Sonoff_Zigbee_Dongle_Firmware/tree/master/Dongle-E/Router
Dongle anstecken, Devicenamen ermitteln (bei mir /dev/ttyACM0) und flashen (passenden Filenamen einsetzen naturgemäß)
ls /dev/serial/by-id
sudo universal-silabs-flasher --device /dev/ttyACM0 flash --firmware ./Z3RouterUSBDonlge_EZNet6.10.3_V1.0.0.gbl
Abstecken und dem Zigbee Netzwerk joinen 😀
Rückflash auf Coordinator ident – man muss nur –sonoff-reset als Parameter mitgeben.
Quelle: https://github.com/NabuCasa/universal-silabs-flasher
Situation: Bluetooth Kopfhörer mit Telefoniefunktion aber ohne Mikrofon.
Problem 1: Registriert sich aber in Windows als Mikrofon und Hands-Free/Freisprechtelefoniegerät.
Problem 2: Webex läuft vollig Amok und Audio ist ungenießbar. Nur Webex. Alle anderen Audioquellen inklusive Teams, Zoom, etc. funktionieren einwandfrei.
Lösung: Hands-Free/Freisprechtelefonie Bluetooth Service beim Kopfhörer Device deaktiveren:
shell:::{A8A91A66-3A7D-4424-8D24-04E180695C7A}
Klassisches Control Panel für Geräte und Drucker geht auf:
Beim gewünschten Gerät (bei mir Sony WH-CH520) “Freisprechtelefonie” (englisch: “Hands-free Telephony”) deaktivieren.