JohannWeiher

Über Johann Weiher

Der Autor hat bisher keine Details angegeben.
Bisher hat Johann Weiher, 531 Blog Beiträge geschrieben.

MuteToHue

Ich hatte ja einen CallMonitor für meine Fritzbox, welcher eine Lampe anschaltet wenn ich telefoniere.
Da wir unsere Telefonanlage nun auf Starface umgestellt haben, musste eine andere Lösung her.

Lange habe ich mir Gedanken gemacht, was hier wohl die beste Lösung ist.
Das Projekt wollte ich unbedingt in .NET Core machen, da ich hier noch nichts gemacht habe.

Da ich nun ausschließlich mit dem Headset telefonieren (dazu noch Skype, WebEx, usw.), läuft das komplette Audio über den Mac.
Wenn ich den Audio-Out mute, weil z.B. Radio läuft, geht das Audio trotzdem am Headset. Das ist sehr angenehm… denn nun musste ich nur noch den Mute-State überprüfen.

Am Mac ist das leider nicht mehr so einfach, aber habe eine Lösung hier gefunden:

public bool GetMuteState()
{
    var readMuteCommand = "osascript -e 'output muted of (get volume settings)'";
    string isMutedString = ReadFromBash(readMuteCommand);
    isMutedString = isMutedString.TrimEnd(Environment.NewLine.ToCharArray()).ToUpper();
    bool newState = isMutedString == "TRUE";
    return newState;
}

public string ReadFromBash(string readMuteCommand)
{
    var escapedArgs = readMuteCommand.Replace("\"", "\\\"");
    var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = "/bin/bash",
            Arguments = $"-c {QUOTE}{escapedArgs}{QUOTE}",
            RedirectStandardOutput = true,
            UseShellExecute = false,
            CreateNoWindow = true,
        }
    };
    process.Start();
    string result = process.StandardOutput.ReadToEnd();
    process.WaitForExit();
    return result;
}

Das überprüfe ich nun alle 5s und wenn sich der Wert ändert, dann wird die Lampe geschalten:

Console.WriteLine("Monitoring mute state...");
bool isMuted = GetMuteState(); // Starting state
while (true)
{
    try
    {
        // Read state
        bool newState = GetMuteState();
        if (isMuted != newState)
        {
            Console.WriteLine("Muted: " + isMuted + " --> " + newState);
            SetHueState(newState);
            isMuted = newState; // All OK, set new state
        }

        Thread.Sleep(SLEEPTIME);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error: " + Environment.NewLine + ex);
    }
}

Aber das Lampen schalten war nicht so einfach…

  • Erster Versuch über Q42.HueApi: Leider stürzt das Programm beim Zugriff auf die Klassen ab
  • Zweiter Versuch über IronPython ein kleine Script zu laden und ausführen: Das Compilieren gestaltet sich bisschen schwierig
  • Lösung: Ich habe ein kleines Python Script mit Platzhalter (True/False) ob die Lampe an ist. Zur Laufzeit ersetzt ich den Wert und führe es über die Bash aus
public void SetHueState(bool newState)
{
    // Read python script and replace placeholder
    var filename = @"/Users/moz/Documents/GitHub/Suplanus.MuteToHue/src/ControlViaPhue.py"; // todo: relative path
    var tempFile = Path.Combine(Path.GetTempPath(), "MuteToHue.py");
    string content = File.ReadAllText(filename, Encoding.UTF8);
    string stateString = FirstCharToUpper(newState.ToString());
    content = content.Replace("$STATE$", stateString);
    File.WriteAllText(tempFile, content, Encoding.UTF8);

    // Execute python script
    var command = $"python {QUOTE}{tempFile}{QUOTE}";
    var result = ReadFromBash(command);
}

public static string FirstCharToUpper(string input)
{
    return input.First().ToString().ToUpper() + input.Substring(1);
}
#!/usr/bin/python

from phue import Bridge
import os
import logging

HUEBRIDGEIP = "192.168.178.79"
LIGHTNAME = "OnAir" # OnAir # Buro

# Init hue
logging.basicConfig()

Bridge = Bridge(HUEBRIDGEIP)
Bridge.connect() # If the app is not registered and the button is not pressed, press the button and call connect() (this only needs to be run a single time)
Bridge.get_api() # Get the bridge state (This returns the full dictionary that you can explore)
light_names = Bridge.get_light_objects('name') # Get a dictionary with the light name as the key
LAMP = light_names[LIGHTNAME] # Get light object
LAMP.on = $STATE$ # True # $STATE$
LAMP.brightness = 254

Das Ganze findet ihr wie gewohnt auf GitHub.

Von |2019-03-13T07:22:19+01:002019-02-16|C#, Projekte|

Fenstermakro an bestimmter Position einfügen

Aufgrund der Diskussion hier, hab ich das ganze mal getestet.
Mit dem Script kann man ein Fenstermakro an auf einer bestimmten Seite mit X- & Y-Koordinaten einfügen.

Mir ist nicht ganz klar was passiert wenn das Laden des Makros (übers Netzwerk) länger dauert. Denke aber dann würde es nicht funktionieren.
Hab hier im Beispiel mal eine Sekunde Wartezeit eingebaut.
Und die Maus sollte beim Ausführen nicht bewegt werden. Denke könnte man auch irgendwie blocken.
Mal ne Idee: Man wartet auf das Resultat des CLI  fürs einfügen.

Danke an SgbMarkus für das Bereitstellen des Codes.

using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Eplan.EplApi.ApplicationFramework;
using Eplan.EplApi.Scripting;

public class Script
{
  [Start]
  public void Action()
  {
    InsertMacro(@"C:\Test\Test.ema", "/2");
  }

  private void InsertMacro(string macroFileName, string pageName)
  {
    Edit(pageName);
    Parallel.Invoke(() =>
                      InsertMacro(macroFileName),
                    KeyPress);
  }

  private static void InsertMacro(string macroFileName)
  {
    ActionCallingContext acc = new ActionCallingContext();
    acc.AddParameter("Name", "XMIaInsertMacro");
    acc.AddParameter("filename", macroFileName);
    acc.AddParameter("variant", "0");
    CommandLineInterpreter cli = new CommandLineInterpreter();
    cli.Execute("XGedStartInteractionAction", acc);
  }

  private static void Edit(string pageName)
  {
    ActionCallingContext acc = new ActionCallingContext();
    acc.AddParameter("PAGENAME", pageName); // Full page name
    acc.AddParameter("X", "100");
    acc.AddParameter("Y", "100");
    CommandLineInterpreter cli = new CommandLineInterpreter();
    cli.Execute("edit", acc);
  }

  private void KeyPress()
  {
    Thread.Sleep(1000);
    SendKeys.SendWait("{ENTER}");
  }
}

 

Von |2019-07-26T09:53:12+02:002019-02-04|EPLAN, EPLAN-Scripts|

Doorbell – Gong

Wir haben ja als Gong eine Funkbox eingesetzt welche über den AUX des Raspberries bespielt wird.
Leider bekommen wir Störgeräusche der Nachbarn rein, welche Funkkopfhörer benutzen. Diese funken wohl auf der gleichen Frequenz.

Nach Tests mit verschiedenen Kanälen (A & B) haben wir aber immer noch Hörspiele der Nachbarn gehört.

Generell war ich nie Fan von der Lösung da die Box und der Sender ständig am Strom hängen.
Ich hatte im Kopf schon die Lösung, aber mir fehlte die Zeit.

Da die Störungen aber immer mehr wurden hab ich mich mal hingesetzt und folgendes umgesetzt:

  • Box weg
  • Audio abspielen über Pi weg
  • Eine Funktürklingel gekauft
  • Den Sender an den Pi über Relais angebunden (12V)
  • Die Gong-Musik von den Kindern einstellen lassen

Technisch ist es nun meiner Meinung nach die bessere Lösung. Einziger Nachteil ist, dass ich die Gong-Musik nicht mehr selbst wählen kann. Somit musste meine geliebtes Super-Mario-Theme weichen.

Der Sender der Türklingel hatte einen SMD Taster den ich entlötet habe. Danach getestet ob es auch ein Schließer ist (ja).
Dort hab ich dann den Relaiskontakt integriert.

Die 12V Batterie vom Sender muss ich noch durch ein Netzteil tauschen wenn Sie oft leer ist.
Hier noch ein Bild der wilden Verdrahtung:

Als Ausgang hab ich die rote LED genommen. Diese ist während der Aufnahme des Fotos aktiv gewesen. Den Code musste ich dem entsprechend anpassen.

 

Von |2019-02-02T11:24:35+01:002019-02-02|Doorbell, Projekte|

Seitenfilter Filtereinstellungen per Script setzen

Nun habe ich schon gezeigt wie man ein Seitenfilter Schema aktiv schalten kann… Und hier seht ihr wie man einzelnen Filtereinstellungen hinzufügen kann.
In diesem Beispiel wird der Filter neu erstellt und eine Filtereinstellung hinzugefügt:

  • Kriterium: Seitenbeschreibung
  • Wert: Test
public class PageFilterExample
{
  private const string SCHEME_NAME = "MyFilter";
  private const string SETTINGS_PATH = "USER.PageBrowserGui.PageFilterScheme";

  [DeclareAction("PageFilterExample")]
  public void Action()
  {
    try
    {
      // Remove filter if exists
      SchemeSetting schemeSetting = new SchemeSetting();
      schemeSetting.Init(SETTINGS_PATH);
      if (schemeSetting.CheckIfSchemeExists(SCHEME_NAME))
      {
        schemeSetting.RemoveScheme(SCHEME_NAME);
      }

      // Create filter
      MultiLangString mlName = new MultiLangString();
      mlName.AddString(ISOCode.Language.L___, SCHEME_NAME);

      MultiLangString mlDescription = new MultiLangString();
      mlDescription.AddString(ISOCode.Language.L___, "My Description");
      schemeSetting.CreateScheme(SCHEME_NAME, mlName, mlDescription);

      SetSchemeSettings();

      // Update page filter
      schemeSetting.SetLastUsed(SCHEME_NAME);
      new Settings().SetBoolSetting("USER.PageBrowserGui.PageFilterScheme.ApplyCheckBox", true, 0);
      EventParameterString eventParameterString = new EventParameterString();
      eventParameterString.String = "RefreshPageFilter";
      new EventManager().Send("RefreshPageFilter", eventParameterString);
    }
    catch (Exception exception)
    {
      var baseException = new BaseException("PageFilterExample: " + exception, MessageLevel.Error);
      baseException.FixMessage();
      new Decider().Decide(EnumDecisionType.eOkDecision, exception.ToString(), "SetPageFilter",
        EnumDecisionReturn.eOK, EnumDecisionReturn.eOK, null, false, EnumDecisionIcon.eFATALERROR);
    }
  }

  private void SetSchemeSettings(int index = 0)
  {
    // Setup path: < is in the default schemes also, don't know why
    const string SETTINGS_PATH_SCHEME_SETTINGS = SETTINGS_PATH + "." + SCHEME_NAME + ".Data<.";

    // Set single (needed) settings
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "Value", "Test", index); // Search value
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "PropDescr", "11011;0", index); // page property id & index
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "Activ", true, index);
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "CriteriaType", 0, index);
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "IgnoreCase", false, index);
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "Negation", false, index);
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "Operator", 0, index);      
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "QuickFilter", false, index);
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "RelationDescr", "0;0", index);
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "SingleValue", false, index);
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "UseWildcards", true, index);      
    SetSchemeSetting(SETTINGS_PATH_SCHEME_SETTINGS + "WholeText", true, index);
  }

  public void SetSchemeSetting(string settingsPath, object value, int index = 0)
  {
    // Add settings nodes (needed because SchemeSetting.Set don't create Settings) & Set filter entries
    var settings = new Settings();
    if (value is bool)
    {
      settings.AddBoolSetting(settingsPath, new[] { (bool)value }, ISettings.CreationFlag.Insert);
      settings.SetBoolSetting(settingsPath, (bool)value, index);

    }
    else if (value is int)
    {
      var range = new[] { new Range { FromValue = 0, ToValue = 32768 } };
      settings.AddNumericSetting(settingsPath, new[] { (int)value }, range, ISettings.CreationFlag.Insert);
      settings.SetNumericSetting(settingsPath, (int)value, 0);

    }
    else if (value is string)
    {
      settings.AddStringSetting(settingsPath, new string[] { }, new string[] { }, ISettings.CreationFlag.Insert);
      settings.SetStringSetting(settingsPath, value.ToString(), 0);
    }
    else if (value is MultiLangString)
    {
      settings.AddMultiLangStringDefault(settingsPath, new MultiLangString[] { }, new MultiLangString[] { }, ISettings.CreationFlag.Insert);
      settings.SetMultiLangStringSetting(settingsPath, (MultiLangString) value, 0);
    }
    else
    {
      throw new NotImplementedException("SetSchemeSetting: Unknow type --> " + value.GetType());
    }
  }

}
Von |2018-11-30T16:16:09+01:002018-12-12|EPLAN, EPLAN-Scripts|

Seitenfilter per Script setzen

Ich hab, mit Hilfe des tollen API-Supports, es geschafft per Script den Seitenfilter zu setzen und diesen auch zu aktivieren.
In diesem Beispiel wird dann der Filter (sofern vorhanden) “MyFilter” im Seitennavigator gesetzt:

const string SCHEME_NAME = "MyFilter";
const string SETTINGS_PATH = "USER.PageBrowserGui.PageFilterScheme";

SchemeSetting schemeSetting = new SchemeSetting();
schemeSetting.Init(SETTINGS_PATH);

// Update page filter
schemeSetting.SetLastUsed(SCHEME_NAME);
new Settings().SetBoolSetting("USER.PageBrowserGui.PageFilterScheme.ApplyCheckBox", true, 0);
EventParameterString eventParameterString = new EventParameterString();
eventParameterString.String = "RefreshPageFilter";
new EventManager().Send("RefreshPageFilter", eventParameterString);
Von |2018-11-30T16:12:00+01:002018-12-11|EPLAN, EPLAN-Scripts|
Nach oben