Skip to content

Commit

Permalink
Merge pull request #27 from geoph9/gnome40
Browse files Browse the repository at this point in the history
add multiple sensor options on preferences menu. they show on the panel. Fixed #25
  • Loading branch information
geoph9 authored Jan 19, 2022
2 parents d535501 + ad577c8 commit e3f690b
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 4 deletions.
116 changes: 113 additions & 3 deletions extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const Utils = Me.imports.utils;

const HASS_TOGGLABLE_ENTITIES = 'hass-togglable-entities';
const HASS_ENABLED_ENTITIES = 'hass-enabled-entities';
const HASS_PANEL_SENSOR_IDS = 'hass-panel-sensor-ids';
const HASS_ENABLED_SENSOR_IDS = 'hass-enabled-sensor-ids';
const HASS_SETTINGS = 'org.gnome.shell.extensions.hass-data';
let hassExtension;

Expand All @@ -30,6 +32,7 @@ var HassExtension = GObject.registerClass ({
if (this.needsRebuild()) {
this.rebuildTray();
this.buildTempSensorStats();
this.buildPanelSensorEntities();
}
}));

Expand All @@ -48,6 +51,8 @@ var HassExtension = GObject.registerClass ({

// Build the temperature/humidity sensor statistics (if needed)
this.buildTempSensorStats();
// Build panel entries for other sensors;
this.buildPanelSensorEntities();
}

rebuildTray() {
Expand Down Expand Up @@ -115,6 +120,37 @@ var HassExtension = GObject.registerClass ({
this.menu.addMenuItem(popupImageMenuItem);
}

buildPanelSensorEntities() {
let panelSensors = this._getSensorEntities();
if (panelSensors.length === 0) {
this._deleteSensorsPanel();
return
}
if (this.sensorsPanel === undefined) {
// Add the temperature in the panel
this.sensorsPanel = new St.Bin({
style_class : "panel-button",
reactive : true,
can_focus : true,
track_hover : true,
height : 30,
});
this.sensorsPanelText = new St.Label({
text : "",
y_align: Clutter.ActorAlign.CENTER,
});
this.sensorsPanel.set_child(this.sensorsPanelText);
this.sensorsPanel.connect("button-press-event", () => {
this._needsRebuildSensorPanel(false);
this._refreshPanelSensors();
});
}

this._refreshPanelSensors();

Main.panel._rightBox.insert_child_at_index(this.sensorsPanel, 1);
}

buildTempSensorStats() {
if (this.showWeatherStats === true) {
if (this.weatherStatsPanel === undefined) {
Expand Down Expand Up @@ -180,6 +216,8 @@ var HassExtension = GObject.registerClass ({

// Do the same for all of the weather entities
trayNeedsRebuild = this._needsRebuildTempPanel(trayNeedsRebuild);
// Do the same for all extra sensor entities
trayNeedsRebuild = this._needsRebuildSensorPanel(trayNeedsRebuild);

return trayNeedsRebuild;
}
Expand Down Expand Up @@ -212,6 +250,34 @@ var HassExtension = GObject.registerClass ({
}
}

/**
*
* @return {Array} An array of objects with keys: 'entity_id' and 'name' to be used when rebuilding the panel entries (the sensors).
*/
_getSensorEntities() {
// Initialize the switched if this is the first time the function is being called
if (this.allSensors === undefined) {
this.allSensors = Utils.discoverSensors(this.base_url);
this._settings.set_strv(HASS_PANEL_SENSOR_IDS, this.allSensors.map(entry => entry.entity_id))
}
if (!this.panelSensorIds || this.panelSensorIds.length === 0) {
// If the sensor entities provided by the user are empty then use nothing
this._settings.set_strv(HASS_ENABLED_SENSOR_IDS, [])
return []
} else {
if (this.allSensors.length === 0) return []
let output = [];
// Only return the entities that appear in the user defined entities
for (let sensor of this.allSensors) {
if (this.panelSensorIds.includes(sensor.entity_id)) {
output.push(sensor);
}
}
this._settings.set_strv(HASS_ENABLED_SENSOR_IDS, output.map(entry => entry.entity_id));
return output
}
}

_toggleEntity(entityId) {
let data = `{"entity_id": "${entityId}"}`;
let domain = entityId.split(".")[0]; // e.g. light.mylight => light
Expand All @@ -234,9 +300,9 @@ var HassExtension = GObject.registerClass ({
try {
let out = "";
// if showWeatherStats is true then the temperature must be shown (the humidity can be turned off)
out += this._getWeatherSensorData(this.tempEntityID);
out += this._getPanelSensorData(this.tempEntityID);
if (this.showHumidity === true) {
out += ` | ${this._getWeatherSensorData(this.humidityEntityID)}`;
out += ` | ${this._getPanelSensorData(this.humidityEntityID)}`;
}
this.weatherStatsPanelText.text = out;
} catch (error) {
Expand All @@ -249,7 +315,33 @@ var HassExtension = GObject.registerClass ({
return true;
}

_getWeatherSensorData(entity_id) {
_refreshPanelSensors() {
try {
let sensorEntities = this._getSensorEntities();
let outText = "";
let tmp;
for (let sensor of sensorEntities) {
tmp = this._getPanelSensorData(sensor.entity_id)
if (!tmp) continue;
outText += `${tmp} | `
}
if (outText.length > 2) {
outText = outText.substring(0, outText.length-3)
}
log("WILL USE OUT TEXT:");
log(outText);
this.sensorsPanelText.text = outText;
} catch (error) {
logError(error, "Could not refresh sensor stats...");
// will execute this function only once and abort.
// Remove in order to make the Main loop continue working.
return false;
}
// By returning true, the function will continue refresing every X seconds
return true;
}

_getPanelSensorData(entity_id) {
let json_result = Utils.send_request(`${this.base_url}api/states/${entity_id}`);
if (!json_result) {
return false;
Expand Down Expand Up @@ -304,6 +396,18 @@ var HassExtension = GObject.registerClass ({
return tempPanelNeedsRebuild;
}

_needsRebuildSensorPanel(trayNeedsRebuild){
let tmp;
// Check togglable ids
tmp = this.panelSensorIds;
this.panelSensorIds = this._settings.get_strv(HASS_ENABLED_SENSOR_IDS);
if (!Utils.arraysEqual(tmp, this.panelSensorIds)) {
trayNeedsRebuild = true;
}
return trayNeedsRebuild;

}

_deleteTempStatsPanel() {

if (this.weatherStatsPanel !== undefined) {
Expand All @@ -313,6 +417,12 @@ var HassExtension = GObject.registerClass ({
}
}
}

_deleteSensorsPanel() {
if (this.sensorsPanel) {
Main.panel._rightBox.remove_child(this.sensorsPanel);
}
}
})


Expand Down
114 changes: 114 additions & 0 deletions prefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ function buildPrefsWidget() {
// TODO
// notebook.append_page(_buildTogglables(), togglables);
notebook.append_page(_buildTogglableSettings(), togglables);

let panelSensors = new Gtk.Label({ label: _('Panel Sensors'), halign: Gtk.Align.START});
notebook.append_page(_buildSensorSettings(), panelSensors);

return prefsWidget;
}
Expand Down Expand Up @@ -374,6 +377,117 @@ function _buildTogglableSettings() {
return scrollWindow;
}

function _buildSensorSettings() {
const mscOptions = new Settings.MscOptions();

const scrollWindow = new Gtk.ScrolledWindow();
let miscUI = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
spacing: 10,
homogeneous: false,
margin_start: 12,
margin_end: 12,
margin_top: 12,
margin_bottom: 12,
hexpand: true,
vexpand: true,
});
let optionsList = [];

// //////////////////////////////////////////////////////////
// ////// Which sensors should be shown on the panel ////////
// //////////////////////////////////////////////////////////
let allSensors = mscOptions.hassSensorIds;
let enabledSensors = mscOptions.enabledSensors;
if (allSensors.length === 0) {
optionsList.push(_optionsItem(
_makeTitle(_('Sensors:')), null, null, null
));
} else {
// Only the title changes
optionsList.push(_optionsItem(
_makeTitle(_('Choose Which Sensors Should Appear on the Panel:')), null, null, null
));
}

// Add the togglable check boxes option
let sensorCheckBoxes = [];
for (let sensor of allSensors) {
let checked = false;
if (enabledSensors.includes(sensor)) checked = true;
let [sensorItem, sensorCheckBox] = _makeCheckBox(sensor, checked);
optionsList.push(sensorItem);
sensorCheckBoxes.push({
entity: sensor,
cb: sensorCheckBox,
checked: checked
});
}



// //////////////////////////////////////////////////////////
// ////////////////// Building the boxes ////////////////////
// //////////////////////////////////////////////////////////
let frame;
let frameBox;
for (let item_id in optionsList) {
let item = optionsList[item_id];
if (!item[0][1]) {
let lbl = new Gtk.Label();
lbl.set_markup(item[0][0]);
frame = new Gtk.Frame({
label_widget: lbl
});
frameBox = new Gtk.ListBox({
selection_mode: null,
can_focus: false,
});
miscUI.append(frame);
frame.set_child(frameBox);
continue;
}
let box = new Gtk.Box({
can_focus: false,
orientation: Gtk.Orientation.HORIZONTAL,
margin_start: 4,
margin_end: 4,
margin_top: 4,
margin_bottom:4,
hexpand: true,
spacing: 30,
});
for (let i of item[0]) {
box.append(i)
}
if (item.length === 2) {
box.set_tooltip_text(item[1]);
}
frameBox.append(box);
}

// //////////////////////////////////////////////////////////
// /////////////// Handlers for Checkboxes //////////////////
// //////////////////////////////////////////////////////////
for (let sensorCheckBox of sensorCheckBoxes) {
sensorCheckBox.cb.set_active(sensorCheckBox.checked)
sensorCheckBox.cb.connect('notify::active', () => {
let currentSensors = mscOptions.enabledSensors;
let index = currentSensors.indexOf(sensorCheckBox.entity);
if (index > -1) { // then it exists and so we pop
currentSensors.splice(index, 1)
} else {
currentSensors.push(sensorCheckBox.entity)
}
mscOptions.enabledSensors = mscOptions.hassSensorIds.filter(ent => currentSensors.includes(ent));
});
}

scrollWindow.set_child(miscUI)

return scrollWindow;
}

function _optionsItem(text, tooltip, widget, button) {
let item = [[],];
let label;
Expand Down
14 changes: 13 additions & 1 deletion schemas/org.gnome.shell.extensions.hass-data.gschema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
<key type="as" name="hass-togglable-entities">
<default>[]</default>
<summary>Complete list of entity ids for home-assistant switches.</summary>
<description>Full list of home assistant switched. It is meant to be filled automatically after pressing the 'Scan' button in the Preferences menu.</description>
<description>Full list of home assistant switches. It is meant to be filled automatically after pressing the 'Scan' button in the Preferences menu.</description>
</key>

<key type="as" name="hass-enabled-entities">
Expand All @@ -89,6 +89,18 @@
<description>Entity ids for home-assistant switches. E.g. switch.livingroom_lights_relay.</description>
</key>

<key type="as" name="hass-panel-sensor-ids">
<default>[]</default>
<summary>Panel Sensors</summary>
<description>List of entity ids for the sensor values that you want to show in the panel .</description>
</key>

<key type="as" name="hass-enabled-sensor-ids">
<default>[]</default>
<summary>Entity ids for home assistant sensors.</summary>
<description>Entity ids for home-assistant sensors. E.g. sensor.livingroom_temperature .</description>
</key>

</schema>

<schema id="org.gnome.shell.extensions.hass-shortcut"
Expand Down
17 changes: 17 additions & 0 deletions settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const HASS_ACCESS_TOKEN = 'hass-access-token';
const HASS_URL = 'hass-url';
const HASS_TOGGLABLE_ENTITIES = 'hass-togglable-entities';
const HASS_ENABLED_ENTITIES = 'hass-enabled-entities';
const HASS_PANEL_SENSOR_IDS = 'hass-panel-sensor-ids';
const HASS_ENABLED_SENSOR_IDS = 'hass-enabled-sensor-ids';
// const HASS_SHORTCUT = 'hass-shortcut';
const SHOW_NOTIFICATIONS_KEY = 'show-notifications';
const SHOW_WEATHER_STATS = 'show-weather-stats';
Expand Down Expand Up @@ -121,4 +123,19 @@ var MscOptions = class MscOptions {
this._gsettings.set_strv(HASS_ENABLED_ENTITIES, entities);
}

// Panel Icons for Extra Sensors
get hassSensorIds() {
return this._gsettings.get_strv(HASS_PANEL_SENSOR_IDS);
}
set hassSensorIds(sensorIds) {
this._gsettings.set_strv(HASS_PANEL_SENSOR_IDS, sensorIds);
}

get enabledSensors() {
return this._gsettings.get_strv(HASS_ENABLED_SENSOR_IDS);
}
set enabledSensors(entities) {
this._gsettings.set_strv(HASS_ENABLED_SENSOR_IDS, entities);
}

}
Loading

0 comments on commit e3f690b

Please sign in to comment.