Prevent errors on Octoprint sensors and binary_sensors when Octoprint and/or Printer are off (#8343)

* Added platformnotready

* Only log the first failure if octoprint/printer isn't up

Remove blank line
This commit is contained in:
William Scanlon 2017-07-07 01:39:11 -04:00 committed by Paulus Schoutsen
parent b67c5df525
commit 652c006cbc
3 changed files with 50 additions and 28 deletions

View File

@ -12,13 +12,12 @@ import voluptuous as vol
from homeassistant.const import CONF_NAME, CONF_MONITORED_CONDITIONS
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['octoprint']
DOMAIN = "octoprint"
DEFAULT_NAME = 'OctoPrint'
SENSOR_TYPES = {
@ -37,7 +36,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the available OctoPrint binary sensors."""
octoprint = get_component('octoprint')
octoprint_api = hass.data[DOMAIN]["api"]
name = config.get(CONF_NAME)
monitored_conditions = config.get(
CONF_MONITORED_CONDITIONS, SENSOR_TYPES.keys())
@ -45,7 +44,7 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
devices = []
for octo_type in monitored_conditions:
new_sensor = OctoPrintBinarySensor(
octoprint.OCTOPRINT, octo_type, SENSOR_TYPES[octo_type][2],
octoprint_api, octo_type, SENSOR_TYPES[octo_type][2],
name, SENSOR_TYPES[octo_type][3], SENSOR_TYPES[octo_type][0],
SENSOR_TYPES[octo_type][1], 'flags')
devices.append(new_sensor)
@ -98,6 +97,3 @@ class OctoPrintBinarySensor(BinarySensorDevice):
except requests.exceptions.ConnectionError:
# Error calling the api, already logged in api.update()
return
if self._state is None:
_LOGGER.warning("Unable to locate value for %s", self.sensor_type)

View File

@ -17,8 +17,6 @@ _LOGGER = logging.getLogger(__name__)
DOMAIN = 'octoprint'
OCTOPRINT = None
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Required(CONF_API_KEY): cv.string,
@ -32,14 +30,15 @@ def setup(hass, config):
base_url = 'http://{}/api/'.format(config[DOMAIN][CONF_HOST])
api_key = config[DOMAIN][CONF_API_KEY]
global OCTOPRINT
hass.data[DOMAIN] = {"api": None}
try:
OCTOPRINT = OctoPrintAPI(base_url, api_key)
OCTOPRINT.get('printer')
OCTOPRINT.get('job')
octoprint_api = OctoPrintAPI(base_url, api_key)
hass.data[DOMAIN]["api"] = octoprint_api
octoprint_api.get('printer')
octoprint_api.get('job')
except requests.exceptions.RequestException as conn_err:
_LOGGER.error("Error setting up OctoPrint API: %r", conn_err)
return False
return True
@ -54,6 +53,11 @@ class OctoPrintAPI(object):
'X-Api-Key': key}
self.printer_last_reading = [{}, None]
self.job_last_reading = [{}, None]
self.job_available = False
self.printer_available = False
self.available = False
self.printer_error_logged = False
self.job_error_logged = False
def get_tools(self):
"""Get the dynamic list of tools that temperature is monitored on."""
@ -62,6 +66,7 @@ class OctoPrintAPI(object):
def get(self, endpoint):
"""Send a get request, and return the response as a dict."""
# Only query the API at most every 30 seconds
now = time.time()
if endpoint == "job":
last_time = self.job_last_reading[1]
@ -73,28 +78,52 @@ class OctoPrintAPI(object):
if last_time is not None:
if now - last_time < 30.0:
return self.printer_last_reading[0]
url = self.api_url + endpoint
try:
response = requests.get(
url, headers=self.headers, timeout=30)
url, headers=self.headers, timeout=9)
response.raise_for_status()
if endpoint == "job":
self.job_last_reading[0] = response.json()
self.job_last_reading[1] = time.time()
self.job_available = True
elif endpoint == "printer":
self.printer_last_reading[0] = response.json()
self.printer_last_reading[1] = time.time()
self.printer_available = True
self.available = self.printer_available and self.job_available
if self.available:
self.job_error_logged = False
self.printer_error_logged = False
return response.json()
except (requests.exceptions.ConnectionError,
requests.exceptions.HTTPError) as conn_exc:
_LOGGER.error("Failed to update OctoPrint status. Error: %s",
conn_exc)
requests.exceptions.HTTPError,
requests.exceptions.ReadTimeout) as conn_exc:
log_string = "Failed to update OctoPrint status. " + \
" Error: %s" % (conn_exc)
# Only log the first failure
if endpoint == "job":
log_string = "Endpoint: job " + log_string
if not self.job_error_logged:
_LOGGER.error(log_string)
self.job_error_logged = True
self.job_available = False
elif endpoint == "printer":
log_string = "Endpoint: printer " + log_string
if not self.printer_error_logged:
_LOGGER.error(log_string)
self.printer_error_logged = True
self.printer_available = False
self.available = False
return None
def update(self, sensor_type, end_point, group, tool=None):
"""Return the value for sensor_type from the provided endpoint."""
response = self.get(end_point)
if response is not None:
return get_value_from_json(response, sensor_type, group, tool)
return response
# pylint: disable=unused-variable
@ -111,3 +140,5 @@ def get_value_from_json(json_dict, sensor_type, group, tool):
elif tool is not None:
if sensor_type in json_dict[group][tool]:
return json_dict[group][tool][sensor_type]
return None

View File

@ -13,13 +13,12 @@ from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (
TEMP_CELSIUS, CONF_NAME, CONF_MONITORED_CONDITIONS)
from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ['octoprint']
DOMAIN = "octoprint"
DEFAULT_NAME = 'OctoPrint'
SENSOR_TYPES = {
@ -38,7 +37,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the available OctoPrint sensors."""
octoprint = get_component('octoprint')
octoprint_api = hass.data[DOMAIN]["api"]
name = config.get(CONF_NAME)
monitored_conditions = config.get(CONF_MONITORED_CONDITIONS)
@ -46,16 +45,16 @@ def setup_platform(hass, config, add_devices, discovery_info=None):
types = ["actual", "target"]
for octo_type in monitored_conditions:
if octo_type == "Temperatures":
for tool in octoprint.OCTOPRINT.get_tools():
for tool in octoprint_api.get_tools():
for temp_type in types:
new_sensor = OctoPrintSensor(
octoprint.OCTOPRINT, temp_type, temp_type, name,
octoprint_api, temp_type, temp_type, name,
SENSOR_TYPES[octo_type][3], SENSOR_TYPES[octo_type][0],
SENSOR_TYPES[octo_type][1], tool)
devices.append(new_sensor)
else:
new_sensor = OctoPrintSensor(
octoprint.OCTOPRINT, octo_type, SENSOR_TYPES[octo_type][2],
octoprint_api, octo_type, SENSOR_TYPES[octo_type][2],
name, SENSOR_TYPES[octo_type][3], SENSOR_TYPES[octo_type][0],
SENSOR_TYPES[octo_type][1])
devices.append(new_sensor)
@ -116,7 +115,3 @@ class OctoPrintSensor(Entity):
except requests.exceptions.ConnectionError:
# Error calling the api, already logged in api.update()
return
if self._state is None and self.sensor_type != "completion":
_LOGGER.warning("Unable to locate value for %s", self.sensor_type)
return