//When mouse is released send the desired volume to HA. private void sliderVol_MouseUp(object sender, MouseEventArgs e) { decimal volumelevel = sliderVol.Value / 100m; Task.Factory.StartNew(() => HAAPI.Volume_Set(volumelevel)); tmrPoll.Start(); }
//Turns on media_player if not already on and if set to do so in settings. void StartupCommands() { if (Properties.Settings.Default.AutoOn) { if (HAData["state"] == "off") { Task.Factory.StartNew(() => HAAPI.Power()); } } if (Properties.Settings.Default.AutoOnSource) { Task.Factory.StartNew(() => HAAPI.Set_Input(Properties.Settings.Default.OnInput)); } if (!String.IsNullOrEmpty(Properties.Settings.Default.StartSwitch)) { Task.Factory.StartNew(() => HAAPI.Toggle_Switch("turn_on", Properties.Settings.Default.StartSwitch)); } if (!String.IsNullOrEmpty(Properties.Settings.Default.ExtraApplication)) { Process.Start(Properties.Settings.Default.ExtraApplication, Properties.Settings.Default.ExtraApplicationArgs); } }
//If left click show context menu with all available HA sources, if right click automatically change to OnInput. private void imgInput_MouseClick(object sender, MouseEventArgs e) { switch (e.Button) { case MouseButtons.Left: contextSources.Show(this, imgInput.Location, ToolStripDropDownDirection.BelowRight); break; case MouseButtons.Right: Task.Factory.StartNew(() => HAAPI.Set_Input()); break; } }
//Populates the source dropdown with all available HA sources. private void cmbOnSource_Click(object sender, EventArgs e) { HAData = HAAPI.GET(Properties.Settings.Default.HAEntity); if (HAData["attributes"].ContainsKey("source_list")) { foreach (string source in HAData["attributes"]["source_list"]) { if (!cmbOnSource.Items.Contains(source)) { cmbOnSource.Items.Add(source); } } } }
//Validates URL when textbox focus is lost. private void txtURL_Leave(object sender, EventArgs e) { if (HAAPI.Validate_URL(txtURL.Text)) { cmbEntity.Enabled = true; cmbOnSource.Enabled = true; } else { MessageBox.Show("Invalid URL, please enter the URL in the following format [PROTO]://[IP or DOMAIN]:[PORT] for example http://192.168.1.10:8123", "HA Volume - Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); cmbEntity.Enabled = false; cmbOnSource.Enabled = false; } }
//Populates the entity dropdown with all HA media_player entities. private void cmbEntity_Click(object sender, EventArgs e) { HAData = HAAPI.GET(); foreach (dynamic item in HAData) { if (item.ContainsKey("entity_id")) { string entityid = item["entity_id"]; if (entityid.Contains("media_player.")) { if (!cmbEntity.Items.Contains(item["entity_id"])) { cmbEntity.Items.Add(item["entity_id"]); } } } } }
private void cmbApplicationStop_Click(object sender, EventArgs e) { HAData = HAAPI.GET(); foreach (dynamic item in HAData) { if (item.ContainsKey("entity_id")) { string entityid = item["entity_id"]; if (entityid.Contains("switch.")) { if (!cmbApplicationStop.Items.Contains(item["entity_id"])) { cmbApplicationStop.Items.Add(item["entity_id"]); } } } } }
//Populates the dropdown with all detected monitors and sets the application version label, disables the dropdowns until valid URL is detected. private void Settings_Load(object sender, EventArgs e) { lblVersion.Text = Application.ProductVersion; Screens = System.Windows.Forms.Screen.AllScreens; foreach (Screen s in Screens) { cmbMonitor.Items.Add(s.DeviceName.Replace("\\\\.\\DISPLAY", "")); } cmbMonitor.SelectedIndex = Properties.Settings.Default.Monitor; if (txtURL.Text == "" || txtToken.Text == "" || HAAPI.Validate_URL(txtURL.Text)) { cmbEntity.Enabled = true; cmbOnSource.Enabled = true; } else { MessageBox.Show("Invalid URL, please enter the URL in the following format [PROTO]://[IP or DOMAIN]:[PORT] for example http://192.168.1.10:8123", "HA Volume - Error", MessageBoxButtons.OK, MessageBoxIcon.Warning); cmbEntity.Enabled = false; cmbOnSource.Enabled = false; } }
//Turns off media_player if not already off and if set to do so in settings. void ShutdownCommands() { if (Properties.Settings.Default.AutoOffSource) { if (HAData["state"] == "on") { Task.Factory.StartNew(() => HAAPI.Set_Input(Properties.Settings.Default.OffInput)); } } if (Properties.Settings.Default.AutoOff) { if (HAData["state"] == "on") { Task.Factory.StartNew(() => HAAPI.Power()); } } if (!String.IsNullOrEmpty(Properties.Settings.Default.StopSwitch)) { Task.Factory.StartNew(() => HAAPI.Toggle_Switch("turn_off", Properties.Settings.Default.StopSwitch)); } }
// This timer runs to update HA constantly, by default every 2 seconds. private void timer1_Tick(object sender, EventArgs e) { PrevHAData = HAData; HAData = HAAPI.GET(Properties.Settings.Default.HAEntity); if (!HAData.ContainsKey("state")) { ntfyMain.ShowBalloonTip(5000, "HA Volume - Connection Lost!", "Unable to communicate with Home Assistant correctly, please confirm Home Assistant is running and accessible from this PC.", ToolTipIcon.Error); } // Update OSD if (HAData.ContainsKey("attributes") && HAData["attributes"].ContainsKey("source")) { lblOSD.Text = HAData["attributes"]["source"]; } else { lblOSD.Text = "Amp Powered Off!"; } // Update Power Icon if (HAData.ContainsKey("state") && HAData["state"] == "on") { this.imgPower.Image = Properties.Resources.on; } else { this.imgPower.Image = Properties.Resources.off; } // Update Mute Icon if (HAData.ContainsKey("attributes") && HAData["attributes"].ContainsKey("is_volume_muted")) { if (HAData["attributes"]["is_volume_muted"]) { this.imgMute.Image = Properties.Resources.mute; } else { this.imgMute.Image = Properties.Resources.vol; } } // Update Slider and Volume Label if (HAData.ContainsKey("attributes") && HAData["attributes"].ContainsKey("volume_level")) { int volaspercent = Convert.ToInt32(HAData["attributes"]["volume_level"] * 100); sliderVol.Value = volaspercent; lblVol.Text = volaspercent.ToString(); } // Show OSD when change in volume or source detected // Messy 'fix' to avoid crash when those paramaters are not supported by the media_player entity // TODO implement better fix try { if (Properties.Settings.Default.OSD && this.Opacity == 0 || PrevHAData.Count > 0 || HAData.Count > 0) { if (HAData.ContainsKey("attributes") && HAData["attributes"].ContainsKey("source")) { if (PrevHAData["attributes"]["source"] != HAData["attributes"]["source"]) { string temp1 = PrevHAData["attributes"]["source"]; string temp2 = HAData["attributes"]["source"]; Task.Factory.StartNew(() => ShowOSD()); } } if (HAData.ContainsKey("attributes") && HAData["attributes"].ContainsKey("volume_level")) { if (PrevHAData["attributes"]["volume_level"] != HAData["attributes"]["volume_level"]) { decimal temp1 = PrevHAData["attributes"]["volume_level"]; decimal temp2 = HAData["attributes"]["volume_level"]; Task.Factory.StartNew(() => ShowOSD()); } } } } catch (System.Collections.Generic.KeyNotFoundException) { } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { tmrPoll.Stop(); SettingsForm.Show(); launchingsettings = true; } }
//Toggles power when power icon clicked. private void imgPower_Click(object sender, EventArgs e) => Task.Factory.StartNew(() => HAAPI.Power());
//Mutes when mute icon clicked. private void imgMute_Click(object sender, EventArgs e) => Task.Factory.StartNew(() => HAAPI.Volume_Mute(HAData["attributes"]["is_volume_muted"]));
// Handle the Global Keybinds. private void _globalHook_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) { //Continue only if CTRL wasn't pressed. if (e.Modifiers != System.Windows.Forms.Keys.Control) { switch (e.KeyCode) { case System.Windows.Forms.Keys.VolumeUp: e.Handled = true; Task.Factory.StartNew(() => HAAPI.Volume_Up()); if (Properties.Settings.Default.OSD && this.Opacity == 0) { Task.Factory.StartNew(() => ShowOSD()); } break; case System.Windows.Forms.Keys.VolumeDown: e.Handled = true; Task.Factory.StartNew(() => HAAPI.Volume_Down()); if (Properties.Settings.Default.OSD && this.Opacity == 0) { Task.Factory.StartNew(() => ShowOSD()); } break; case System.Windows.Forms.Keys.VolumeMute: if (!Properties.Settings.Default.DisableMute) { e.Handled = true; bool state = HAData["attributes"]["is_volume_muted"]; Task.Factory.StartNew(() => HAAPI.Volume_Mute(state)); } break; // Pressing the Pause key without Shift will toggle power, with Shift it changes to the OnInput. case System.Windows.Forms.Keys.Pause: e.Handled = true; if (e.Modifiers == System.Windows.Forms.Keys.Shift) { Task.Factory.StartNew(() => HAAPI.Set_Input()); } else { Task.Factory.StartNew(() => HAAPI.Power()); } break; // Pressing the Scroll key without Shift will turn on additional switch, with Shift it turns off additional switch. case System.Windows.Forms.Keys.Scroll: e.Handled = true; if (e.Modifiers == System.Windows.Forms.Keys.Shift) { Task.Factory.StartNew(() => HAAPI.Toggle_Switch("turn_off", Properties.Settings.Default.StopSwitch)); } else { Task.Factory.StartNew(() => HAAPI.Toggle_Switch("turn_on", Properties.Settings.Default.StartSwitch)); } break; default: break; } } }
//This is a workaround to be able to add seperate events to each dynamic context menu entry (source). void contextsource(object sender, EventArgs e) => Task.Factory.StartNew(() => HAAPI.Set_Input(sender.ToString()));
private void Main_Load(object sender, EventArgs e) { foreach (string arg in Environment.GetCommandLineArgs()) { if (arg == "/updated") { Properties.Settings.Default.Upgrade(); Properties.Settings.Default.Save(); } } SystemEvents.PowerModeChanged += OnPowerModeChanged; this.Opacity = 0; //If HAURL is not set or url is invalid, assume first launch and load settings. if (String.IsNullOrEmpty(Properties.Settings.Default.HAURL) || !HAAPI.Validate_URL(Properties.Settings.Default.HAURL)) { SettingsForm.Show(); launchingsettings = true; //If HAURL is set then continue as normal. } else { lblOSD.Text = "HA Volume - " + System.Windows.Forms.Application.ProductVersion; //Check for Updates. if (Properties.Settings.Default.Update) { AutoUpdaterDotNET.AutoUpdater.Start("http://cyanlabs.net/api/latest.php?product=" + System.Windows.Forms.Application.ProductName); } //Set OSD to the correct screen based on settings. int x = Screen.AllScreens[Properties.Settings.Default.Monitor].Bounds.Location.X + (Screen.AllScreens[Properties.Settings.Default.Monitor].WorkingArea.Width - this.Width); int y = Screen.AllScreens[Properties.Settings.Default.Monitor].Bounds.Location.Y + (Screen.AllScreens[Properties.Settings.Default.Monitor].WorkingArea.Height - this.Height); Location = new Point(x, y); //Runs a manual poll to prevent crash before timer has run. HAData = HAAPI.GET(Properties.Settings.Default.HAEntity); //Populates menu with all sources set in HA. try { if (HAData["attributes"].ContainsKey("source_list")) { foreach (string source in HAData["attributes"]["source_list"]) { contextSources.Items.Add(source, null, contextsource); } } } catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException) { tmrPoll.Stop(); SettingsForm.Show(); launchingsettings = true; } //If Keybinds are enables it adds the keybind event handler. if (Properties.Settings.Default.Keybinds) { _globalHook = Hook.GlobalEvents(); _globalHook.KeyDown += _globalHook_KeyDown; } //Set timer to 1000 x chosen poll speed and start the timer. tmrPoll.Interval = Properties.Settings.Default.PollRate * 1000; tmrPoll.Start(); StartupCommands(); } }