Access to Enclosure Plugin Temperature and Humidity Data via Python

The Dashboard plugin accesses the Enclosure plugin view model (specifically sensor label, temperature and humidity) through Jinja. Can someone please refer me to an example in which the Enclosure plugin view model is accessed by another OctoPrint plugin using Python?

  /home/pi/oprint/lib/python3.7/site-packages/octoprint_dashboard/templates/dashboard_tab.jinja2

  <!-- Enclosure Sensors -->
  <!-- ko if: enclosureViewModel -->
  <!-- ko foreach: enclosureViewModel.rpi_inputs_temperature_sensors() -->
  <div class="dashboardGridItem enclosure"
    data-bind="visible: $parent.settingsViewModel.settings.plugins.dashboard.showSensorInfo() && $parent.fsSensorInfo()">
    <img class="dashboardIcon" title="Sensor temp (target temp)"
      src="plugin/dashboard/static/img/ambient-sensor-icon.png">
    <div class="inline">
      <span id="HumiditySensorInfo" data-bind="text: label, attr: {title: label}"></span><br />
      <span id="TempSensorInfo"
        data-bind="attr: { title: 'Ambient Temp Sensor' }, html: temp_sensor_temp() + '°C'"></span>
      <!-- ko if: temp_sensor_humidity -->
      <span class="dashboardSmall" id="HumiditySensorInfo"
        data-bind="attr: { title: 'Ambient Humidity Sensor' }, html: temp_sensor_humidity() + '%'"></span>
      <!-- /ko -->
    </div>
  </div>
  <!-- /ko -->
  <!-- /ko -->

ViewModels live in javascript. You can extract data from the viewmodel and send it to Python to do something with there, but you cannot directly access it from Python. Often pieces of data that are represented in the ViewModel actually originate in Python, such as the state of sensors in this case. So if you want to access that data from python, you should "catch" that data before it is passed to javascript.

Or, what I should actually be saying:

ViewModels are a client thing so they live in the browser. You can extract data from the ViewModel and send it to the server to do something with there, but you cannot directly access it from the server. Often pieces of data that are represented in the ViewModel actually originate from the server, such as the state of sensors in this case. So if you want to access that data from something running on the server, you should "catch" that data before it is passed to the browser.

2 Likes

Like FormerLurker said, you can bind to the front end js side, but not the python side. But, there is a PR pending on the Enclosure plugin that would allow you to do what you're attempting I think. It injects that data into the temperature data and allows for things like my PlotlyTempGraph plugin to use that data to graph. Have had multiple reports that it works.

1 Like

In October 2019, when StefanCohen (Dashboard plugin) and UnchartedBull (OctoDash) first proposed accessing Enclosure plugin temperature sensor data, StefanCohen said to vitormhenrique,

I haven't investigated your viewModel or API yet. I have a feeling that it is probably possible to get the info via those mechanisms but I see two problems with that:

1. The viewModel approach makes the solution fragile and vulnerable to UI changes on your end.
2. The API requires user configuration.

I propose that you implement support for custom events via the OctoPrint eventManager.

I assume (?) the custom events were never implemented. From the Dashboard plugin code I referenced, it would appear StefanCohen settled on the view model approach. It would appear UnchartedBull contributed to the Enclosure plugin API v2.0.

The API v2.0 should satisfy my needs.

Thank you for the help!

I experimented with the octoprint.comm.protocol.temperatures.received hook. That would be an option as well if Dak0r's changes are incorporated into the Enclosure plugin. Your temperature graphs would be an added bonus.

Is there a way to save the temperature graphs along with all the other pertinent information on a per-print basis?

In my plugin's current implementation no, I'm hiding the modebar at the top that gives a save button to png, but please feel free to post and issue on the repo requesting that feature.

Just FYI ...

I discovered the Enclosure plugin "plugin/enclosure/outputs" API only returns "regular" outputs,

    octoprint_enclosure/__init__.py

    @octoprint.plugin.BlueprintPlugin.route("/outputs", methods=["GET"])
    def get_outputs(self):
        outputs = []
        for rpi_output in self.rpi_outputs:
            if rpi_output['output_type'] == 'regular':  ### WTF?
                index = self.to_int(rpi_output['index_id'])
                label = rpi_output['label']
                pin = self.to_int(rpi_output['gpio_pin'])          
                ActiveLow = rpi_output['active_low']
                val = PinState_Human(pin,ActiveLow)
                outputs.append(dict(index_id=index, label=label, GPIO_Pin=pin, State=val))
        return Response(json.dumps(outputs), mimetype='application/json')

I can't fathom why. There are nine different types of outputs. I've opened an issue,

My goal is to identify outputs corresponding to temperature/humidity-controlled "enclosures" ("output_type": "temp_hum_control"). More important than the enclosure itself, I'm interested in one or more filament dryers ... each with a target temperature, actual temperature and actual humidity. All of the information and functionality is currently available in the Enclosure plugin, I'd just like to streamline the steps through which the information is accessed. Of course, a few "tweaks" to the Dashboard plugin are required to display something other than the actual temperature and humidity (mockup below). I'm trying to sort out whether this will be addressed as part of V2 of the Dashboard plugin,

ETA: I meant target temperatures.

May I ask where you're getting the target temperatures in the case of "chamber", "test" and "test2" in this screenshot? It wouldn't appear as if they're coming from Dak0r's changes to the Enclosure plugin via the octoprint.comm.protocol.temperatures.received hook. Dak0r is only adding the actual temperature (and humidity) to the hook dataset corresponding to inputs of input_type temperature_sensor.

Chamber comes from printer firmware, the test ones are from my sample test plugin, that just throws in random data.

Thank you!

As I'm sure you're aware, in the case of the heatbed ('B') and nozzle ('T0'), the actual and target temperatures are added to the octoprint.comm.protocol.temperatures.received hook dataset,

    {'B': (69.6, 70.0), 'T0': (239.6, 240.0)}

Dak0r's changes to the Enclosure plugin only consider inputs with input_type == temperature_sensor (blue box in the attached drawing) and yields (logically),

	label + " Temperature Actual": temp_sensor_temp
	label + " Humidity Actual": temp_sensor_humidity

For completeness, considering the target temperature (temp_ctr_set_value) of Enclosure plugin outputs with,

    output_type == temp_hum_control and a control_type == "heater"

and the alarm temperature (alarm_set_temp) with,

    output_type == temperature_alarm

would yield,

	label + " Temperature Actual": temp_sensor_temp
	label + " Temperature Target": temp_ctr_set_value
	label + " Humidity Actual": temp_sensor_humidity

and,

	label + " Temperature Actual": temp_sensor_temp
	label + " Temperature Alarm": alarm_set_temp
	label + " Humidity Actual": temp_sensor_humidity

These are temperature controllers and temperature alarms modelled as an output (red box) and the one-way association (red dashed arrows) with an input (blue box). It's not enough to only consider Enclosure plugin inputs.

With the temperature controllers corresponding to the heatbed and nozzle, the actual temperature is more meaningful with the target temperature. The same is true of an Enclosure plugin temperature controller corresponding to the enclosure, filament dryers, ... The alarm temperature may be interesting in the context of a temperature alarm.

"Who would I talk to" if I wanted the temperature controller table under the temperature graph extended to include the actual and target temperatures "discovered" via the octoprint.comm.protocol.temperatures.received hook? Refer to my mockup below.

Of course, changes to the target temperatures would need to be "posted / patched" back to the plugin from which they came. For example, if the target temperature came from the Enclosure plugin (rpi_outputs.temp_ctr_set_value), changes to the target temperature (via the temperature controller table) would need to be posted / patched back to the Enclosure plugin.

If you can help me understand "who" would be best suited to implement this, I can target the feature request to the appropriate plugin.

Thanks again, @jneilliii!

That would probably have to happen in my plugin, but as you already pointed out there would have to be a way to know where it came from and how to implement the command for changes, etc. That could be a huge undertaking but I would be more than happy to implement this feature because it makes sense. I think the best approach would probably be creating custom event hooks in my plugin that these additional options would trigger and then allow the originating plugin to react to those event hooks being triggered. Hopefully that makes sense. Post a feature request on the repo and we can brainstorm it further there, and link back here as well.

After further review ...

The temperature controller target temperature is specified under the Enclosure plugin "tab" (see below). I can't justify asking you (or anyone else) to move this to the Temperature tab. Sorry for the confusion.

I still think the PlotlyTempGraph plugin would benefit from having access to the Enclosure plugin temperature controller target temperature (to graph alongside the actual temperature). As we discussed, this would involve modifying Dak0r's changes to the Enclosure plugin in order to add the target temperature to the octoprint.comm.protocol.temperatures.received hook.

I incorrectly identified the Enclosure plugin temperature controller target temperature as temp_ctr_max_temp. There is in fact a temp_ctr_max_temp associated with a temperature controller, however, the target temperature is captured in temp_ctr_set_value (set under the Enclosure plugin tab).

I'd also suggested the Enclosure plugin temperature alarm was a form of temperature controller (given that it associates an output with an input of input_type == temperature_sensor in the same way as a temperature controller) when it fact it's not. The alarm temperature is set under OctoPrint Settings as alarm_set_temp. Temperature alarms do not appear under the Enclosure plugin tab as with temperature controllers. However, it may still make sense to add the alarm temperature to the octoprint.comm.protocol.temperatures.received hook.