Wednesday, July 24, 2013

NEC MultiSync Ethernet Remote Control

Two years back I bought NEC MultiSync V321 one of the reasons was it have ethernet port and you can control it over the network.
The other reason is that there is documentation for it provided by NEC which can help you with commands, if you are intelligent and good enough to understand it. Which is probably not my case.
However NEC also offers NEC PD comms tool, which is application which let you control your NEC.
As I have Yamaha AV reciever (for which Yamaha provides control app) my intention recently was to have small app just to switch on/off the monitor and so limit number of remote controlers.
I also recently bought raspberry Pi and find good use for it. I'm running web server there and using cgi I can switch on/off my NEC and also Yamaha (will write about it in future as I will implement more features).
So what I did, I used NEC PD comms tool and wireshark to catch the tcp data payload for on and off, I wrote few lines in python to send those data and add few more to work nicely as cgi.

Here are the source codes:

NECOn.py
#! /usr/bin/python

import socket

monitor_ip = '10.0.0.35'
port = 7142
buffer_size = 1024
data_on = '\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x30\x33\x44\x36\x30\x30\x30\x31\x03\x73\x0d'

new = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
new.connect((monitor_ip, port))
new.send(data_on)
recv_data = new.recv(buffer_size)
new.close()

print """
<html>
  <head>
    <meta http-equiv="refresh" content="0;url=http://10.0.0.37" />
    <title>You are going to be redirected</title>
  </head>
  <body>
    Redirecting...
  </body>
</html>
"""

NECOff.py
#! /usr/bin/python

import socket

monitor_ip = '10.0.0.35'
port = 7142
buffer_size = 1024
data_off = '\x01\x30\x41\x30\x41\x30\x43\x02\x43\x32\x30\x33\x44\x36\x30\x30\x30\x34\x03\x76\x0d'


mon_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mon_socket.connect((monitor_ip, port))
mon_socket.send(data_off)
recv_data = mon_socket.recv(buffer_size)
mon_socket.close()

print """
<html>
  <head>
    <meta http-equiv="refresh" content="0;url=http://10.0.0.37" />
    <title>You are going to be redirected</title>
  </head>
  <body>
    Redirecting...
  </body>
</html>
"""
For monitoring purpose I needed to find the howto check status of my NEC and recorded in the Database(I use sqlite3), even the response is just 25 bytes NEC dived it into 2 packets, so we are recording all packets and then check if the On or Off. NECStatus.py
#! /usr/bin/python

import sys
import socket
import sqlite3

monitor_ip = '10.0.0.35'
port = 7142
buffer_size = 2048
data_on = '\x01\x30\x41\x30\x41\x30\x36\x02\x30\x31\x44\x36\x03\x74\x0d'


new = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
new.connect((monitor_ip, port))
new.send(data_on)

data = ''

#message is split over several packets so need to get all content, message we expect have 25bytes
packet = new.recv(buffer_size)
data += packet
while len(data) < 25 or not packet:
   packet = new.recv(buffer_size)
   data += packet

new.close()

#Reponse OFF
#00AB120200D60000040004q
#Response ON
#00AB120200D60000040001t

off_response = b'\x30\x30\x41\x42\x31\x32\x30\x32\x30\x30\x44\x36\x30\x30\x30\x30\x30\x34\x30\x30\x30\x34'
on_response = bytes("\x30\x30\x41\x42\x31\x32\x30\x32\x30\x30\x44\x36\x30\x30\x30\x30\x30\x34\x30\x30\x30\x31")


#there seems to be some not printable chars because of packet fragmentation
#using index is dirty hack but don't care
if data[23] == off_response[21]:
  power_status = "Off"
elif data[23] == on_response[21]:
  power_status = "On"
else:
  power_status = "Unknown"

#Now we need to update sqlite with status

select_query = "SELECT cur_state,polls_in_state FROM dev_status WHERE mac = '00:25:5c:2e:36:39';"
#print update_query
new_polls=1

judodb = sqlite3.connect('/var/www/judo.db')
cur = judodb.cursor()
rows = cur.execute(select_query)
for row in rows:
  prev_state = row[0]
  prev_polls = row[1]
if prev_state == power_status:
  new_polls = prev_polls + 1
print prev_state + "\t\t" + str(new_polls)
update_query = "UPDATE dev_status SET cur_state = \'" + power_status + "\', polls_in_state = " + str(new_polls)  + " WHERE mac = '00:25:5c:2e:36:39'"
cur.execute(update_query)
judodb.commit()
judodb.close()

If you have any questions you can always contact me.