Background

If you have an Onkyo receiver, you probably notice odd issues with the network stack at times, causing various services (Spotify, DLNA, Etc) to stop responding to requests. The only resolution for fixing this state on the receiver is a physical power cycle (A soft reboot will not work). This is a well documented issue. It’s been blamed on faulty hardware, but it’s really a bug in the network stack somewhere causing this state.



Due to this issue, I decided to use Python to automate monitoring my receiver service status, log the results, and talk to my home automation platform to power cycle the plug it’s using for AC power if the service no longer responds. Let’s break down my script – (If you’d like to skip ahead, just grab the python script from below, install the required Onkyo-EISCP library and modify the variables to suit your environment, and run on a schedule with cron)

Functions accomplished by the final script –

Uses the Onkyo-EISCP python library to try to send a EISCP command to the receiver.

This is the only reliable way to determine if the various media services on the receiver are in a working state. When the receiver is in this state, the web server will still respond, and it will function normally otherwise, so EISCP commands must be sent to see if a response will be generated. This is the basis of the “health check”.

Sends a measurement to InfluxDB in the form of a integer that will be “0” for failed connectivity, and will be the reverse for a successful connection

This measurement is charted with Grafana, and a health check is built around it that will send a slack notification on any failure

Creates a small function to talk to my Vera Lite zwave automation controller.

This controller has a smart power switch associated with it that the receiver uses for power.

Script Breakdown

To begin, we define the variables needed to talk to the following –

InfluxDB

Vera Lite HTTP API

Onkyo Reciever

#Define Vera URL url = 'http://vera.local:49451/data_request?' #Define receiver IP receiver = eiscp.eISCP('192.168.99.134') #Define vera request params vera_switch_on = { 'id': 'action', 'DeviceNum': '77', 'serviceId': 'urn:upnp-org:serviceId:SwitchPower1', 'action': 'SetTarget', 'newTargetValue': '1', } vera_switch_off = { 'id': 'action', 'DeviceNum': '77', 'serviceId': 'urn:upnp-org:serviceId:SwitchPower1', 'action': 'SetTarget', 'newTargetValue': '0', } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #Define Vera URL url = 'http://vera.local:49451/data_request?' #Define receiver IP receiver = eiscp . eISCP ( '192.168.99.134' ) #Define vera request params vera_switch_on = { 'id' : 'action' , 'DeviceNum' : '77' , 'serviceId' : 'urn:upnp-org:serviceId:SwitchPower1' , 'action' : 'SetTarget' , 'newTargetValue' : '1' , } vera_switch_off = { 'id' : 'action' , 'DeviceNum' : '77' , 'serviceId' : 'urn:upnp-org:serviceId:SwitchPower1' , 'action' : 'SetTarget' , 'newTargetValue' : '0' , }

The Vera API talks in JSON format, So we define a multi-line dict that contains the information needed to control our power switch (Id, Device Number, Service ID, action, and target value). We also define a EISCP library object with the IP of our receiver for later use.

Next, we create a simple function that will send a http GET request with our previously defined JSON dict objects depending on the condition we encounter.

def vera_request(qry): s = requests.Session() req = requests.Request(method='GET', url=url) prep = req.prepare() prep.url = url + qry r = s.send(prep) 1 2 3 4 5 6 def vera_request ( qry ) : s = requests . Session ( ) req = requests . Request ( method = 'GET' , url = url ) prep = req . prepare ( ) prep . url = url + qry r = s . send ( prep )

The main part of the script is a try/except/else flow.

First, we try to send a EISCP command (dimmer-level-bright) to the receiver using the EISCP library

try: #Try to send a command to the reciever receiver_status = receiver.command('dimmer-level=bright') 1 2 3 try : #Try to send a command to the reciever receiver_status = receiver . command ( 'dimmer-level=bright' )

If we encounter any exception, we run some logic to write a measurement to InfluxDB, then power cycle the receiver, using our previously created function (vera_request) and dict objects (vera_switch_on/off)

except: print("Cant connect to onkyo") receiver_reachable = 0 json_body = [ { "tags": { "host": "onkyo", }, "measurement": "reachable", "fields": { "int_value": receiver_reachable } } ] client.write_points(json_body) print("Turning Receiver off") vera_request(vera_switch_off_qry) #Sleep 5 time.sleep(5) print("Turning Receiver on") vera_request(vera_switch_on_qry) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 except : print ( "Cant connect to onkyo" ) receiver_reachable = 0 json_body = [ { "tags" : { "host" : "onkyo" , } , "measurement" : "reachable" , "fields" : { "int_value" : receiver _ reachable } } ] client . write_points ( json_body ) print ( "Turning Receiver off" ) vera_request ( vera_switch_off_qry ) #Sleep 5 time . sleep ( 5 ) print ( "Turning Receiver on" ) vera_request ( vera_switch_on_qry )

If we don’t encounter any exception, we jump down to the else and simply print a message to the console, and log the result to InfluxDB

lse: print('Success - Receiver Conencted!') receiver_reachable = 1 json_body = [ { "tags": { "host": "onkyo", }, "measurement": "reachable", "fields": { "int_value": receiver_reachable } } ] client.write_points(json_body) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 lse : print ( 'Success - Receiver Conencted!' ) receiver_reachable = 1 json_body = [ { "tags" : { "host" : "onkyo" , } , "measurement" : "reachable" , "fields" : { "int_value" : receiver _ reachable } } ] client . write_points ( json_body )

Here’s the script in total –

Here’s a sample grafana dashboard that will graph this data. You can download the dashboard layout here.

The CLI output from the script looks like this –

Sample slack notification