Hi, utter noob, so be gentle. No experience of EventGhost, or Python.
I have started a plugin for Serial Control of the 340R Receiver which is based on the plugin for the 840A that's included with EventGhost. The Protocol is the same, but the commands are different.
I cannot for the life of me get the Receiver to "act" on the commands, however.
It's talking to EventGhost okay, when I turn the volume knob, or select sources/input etc on the Receiver, the event is triggered in event ghost.
But "sending" commands does not work - the receiver does not respond. I have controled this amp before (but not from this PC), so unless the commands aren't actually as they appear (I worry about the "/r" or carriage return that's needed).
Any pointers?
Notice: This forum has been recovered from an old backup, so some content, links, and dates may be outdated. The forum is currently read-only while we restore sign-in and registration functionality. Details
If you find this forum valuable and would like to help keep it online, donations to help cover hosting and domain costs are greatly appreciated, but never expected. You can support the forum through Buy Me a Coffee or Ko-fi. Thank you for helping preserve the EventGhost community.
If you find this forum valuable and would like to help keep it online, donations to help cover hosting and domain costs are greatly appreciated, but never expected. You can support the forum through Buy Me a Coffee or Ko-fi. Thank you for helping preserve the EventGhost community.
Serial Control Cambridge Audio 340R
-
cafe.racer
- Posts: 6
- Joined: Fri Dec 23, 2011 8:41 pm
Re: Serial Control Cambridge Audio 340R
Code: Select all
#
# CambridgeAudioAzur540RSerial V0.1
# ================
# Based on work by Pavel Ivanov aka Johnson, <[email protected]>
# Public Domain
#
# Revision history:
# -----------------
# 0.1 - (23.12.11) initial
import eg
help = '''\
Plugin based on Pavel Ivanov's plugin for the 840A adapted for the Azur 340R/540R.
'''
eg.RegisterPlugin(
name = 'CambridgeAudio Azur 340R/540R Serial',
author = 'cafe.racer',
version = '0.1',
kind = 'external',
description = 'Control Cambridge Audio 340R/540R via RS232',
help = help,
canMultiLoad = True,
createMacrosOnAdd = True,
)
import threading
import time
import re
class conf:
FirstVolumeRepeatPause = 0.3
NextVolumeRepeatPause = 0.110
class current:
Volume = 45
Mute = False
cmdList = (
('Power', None, None, None),
('PowerOn', 'Power On', '1,01,1', None),
('PowerOff', 'Power Off', '1,01,0', None),
('Volume', None, None, None),
('MuteOff', 'Mute Off', '1,12,0', None),
('MuteOn', 'Mute On', '1,12,1', None),
('VolumeGoto', 'Goto Volume x (00-50, 50=0dB)', '1,13,x', '00-50'),
('VolumeUp', 'Volume Up', '1,02', None),
('VolumeDown', 'Volume Down', '1,03', None),
('Parameters', None, None, None),
('BassUp', 'Bass Up', '1,04', None),
('BassDown', 'Bass Down', '1,05', None),
('TrebleUp', 'Treble Up', '1,06', None),
('TrebleDown', 'Treble Down', '1,07', None),
('SubOn', 'Sub On', '1,08', None),
('SubOff', 'Sub Off', '1,09', None),
('SetLFEtrim', 'Set LFE trim (0 = 0db, 1 = -1db to -10 = -10dB)', '1,10,x', '00-10'),
('MuteOn', 'Mute On', '1,11,01', None),
('MuteOff', 'Mute Off', '1,11,00', None),
('DynamicRangeSet', 'Dynamic Range Set (0 - 0/4, 1 - 1/4, 2 - 2/4, 3 - 3/4, 4 - 4/4)', '1,12,x', '00-04'),
('Sources', None, None, None),
('InputSelect', 'Input Select (1 - DVD, 2 - Video 1, 3-Tuner, 4 - Video2, 5 - Video3, 6 - Tape/MD/CDR, 7 - CD/Aux, 8 - 6.1 Direct In)', '2,01,x', '01-08'),
('InputDVD', 'DVD', '2,01,01', None),
('InputVideo1', 'Video 1', '2,01,02/r', None),
('InputVideo2', 'Video 2', '2,01,04/r', None),
('InputVideo3', 'Video 3', '2,01,05', None),
('InputTuner', 'Tuner', '2,01,03', None),
('InputTape', 'Tape/MD/CDR', '2,01,06', None),
('InputCD', 'CD/Aux', '2,01,07', None),
('InputDirect', '6.1 Direct In', '2,01,08', None),
('InputUp', 'Next Source Up', '2,02', None),
('InputDown', 'Next Source Down', '2,03', None),
('InputMode', 'Set Input Mode (00=Analogue 01=Digital)', '2,04,x', '00-01'),
('Audio Processing', None, None, None),
('SetAudiotoStereo', 'Set Audio to Stereo', '4,01,00', None),
('SetAudiotoStereoSub', 'Set Audio to Stereo + Sub', '4,01,01', None),
('SetPLIINeo', 'Set PLII/Neo', '4,02', None),
('SetDDDTS', 'Set DD/DTS', '4,03', None),
('GetCurrentDSPmode', 'Get Current PLII/Neo/DSP mode', '4,04', None),
('GetcurrentDDDTSmode', 'Get current DD/DTS mode', '4,05', None),
('SetDSPCycles', 'Set DSP Cycles', '4,06', None),
('Version', None, None, None),
('SoftwareVersionGet', 'Get Software Version', '5,01,', None),
('ProtocolVersionGet', 'Get Protocol Version', '5,02,', None),
('Tuner', None, None, None),
('TunerStereo', 'Tuner Stereo', '3,01,00', None),
('TunerMono', 'Tuner Mono', '3,01,01', None),
('FrequencyUp', 'Frequency Up', '3,02', None),
('FrequencyDown', 'Frequency Down', '3,03', None),
('Up', 'Up', '3,04', None),
('Down', 'Down', '3,05', None),
('TunerMode', 'Tuner Mode', '3,06', None),
('TunerSearchStop', 'Tuner Search Stop', '3,07', None),
('TunerAutoSearch', 'Tuner Auto Search', '3,08', None),
('TunerBand', 'Tuner Band', '3,09', None),
('TunerPTYSelect', 'Tuner PTY Select', '3,10', None),
('StoreStation', 'Store Station', '3,11', None),
('GetPreset', 'Get Preset', '3,12', None),
('TunerDisplyMode', 'Tuner Disply Mode', '3,13', None),
('GetFrequency', 'Get Frequency', '3,14', None),
('GetStationName', 'Get Station Name', '3,15', None),
('GetPTY', 'Get PTY', '3,16', None),
('StopPTYSelect', 'Stop PTY Select', '3,17', None),
(None,None,None,None),
)
EventList = {
'11':{
'content':'Error',
'01':'Command Group Unknown',
'02':'Command Number in Group Unnown',
'03':'Command Data Error'
},
'6':{
'content':'Amplifier',
'01':'Power State',
'02':'Volume Up',
'03':'Volume Down',
'04':'Bass Up',
'05':'Bass Down',
'06':'Treble Up',
'07':'Treble Down',
'08':'Sub On',
'09':'Sub Off',
'10':'Set LFE trim',
'11':'Mute On State',
'12':'Dynamic Range Set',
'13':'OSD On',
'14':'OSD Off',
'15':'OSD Up',
'16':'OSD Down',
'17':'OSD Left',
'18':'OSD Right',
'19':'OSD Enter'
},
'7':{
'content':'Source',
'01':'Input Select',
'02':'Next Input Up',
'03':'Next Input Down',
'04':'Input Mode'
},
'8':{
'content':'Tuner',
'01':'Tuner Stereo/Mono',
'02':'Frequency Up',
'03':'Frequency Down',
'04':'Up',
'05':'Down',
'06':'Tuner Mode',
'07':'Tuner Search Stop',
'08':'Tuner Auto Search',
'09':'Tuner Band',
'10':'Tuner PTY Select',
'11':'Store Station',
'12':'Get Preset',
'13':'Tuner Diaply Mode',
'14':'Get Frequency',
'15':'Get Station Name',
'16':'Get PTY',
'17':'Stop PTY Select'
},
'9':{
'content':'Audio Processing',
'01':'Set Audio to Stereo',
'02':'Set PLII/Neo/DSP',
'03':'DD/DTS',
'04':'Get current PLII/Neo/DSP mode',
'05':'Get current DD/DTS Mode'
},
'10':{
'content':'Version',
'01':'Software Version',
'02':'Protocol Version'
}
}
class CmdAction(eg.ActionClass):
'''Base class for all argumentless actions'''
def __call__(self):
self.plugin.serialThread.SuspendReadEvents()
self.plugin.serialThread.Write('#' + self.cmd + chr(13))
self.plugin.serialThread.ResumeReadEvents()
class ValueAction(eg.ActionWithStringParameter):
'''Base class for all actions with adjustable argument'''
def __call__(self, data):
self.plugin.serialThread.SuspendReadEvents()
self.plugin.serialThread.Write('#' + self.cmdLeft + str(data) + self.cmdRight + chr(13))
self.plugin.serialThread.ResumeReadEvents()
class Raw(eg.ActionWithStringParameter):
name = 'Send Raw command'
def __call__(self, data):
self.plugin.serialThread.SuspendReadEvents()
self.plugin.serialThread.Write(str(data) + chr(13))
self.plugin.serialThread.ResumeReadEvents()
class VolumeAction(eg.ActionClass):
def __call__(self):
self.VolumeThread = threading.Thread(
target=self.VolumeThreadLoop,
name="VolumeThread",
args=(eg.event, current.Volume, self.increment,)
)
self.VolumeThread.start()
def VolumeThreadLoop(self, event, vol, increment):
firstLoop = True
while not event.isEnded:
vol += increment
if (vol < 1) or (vol > 96): break
self.plugin.serialThread.SuspendReadEvents()
self.plugin.serialThread.Write('#1,02,' + format(vol, '02d') + chr(13))
self.plugin.serialThread.ResumeReadEvents()
if firstLoop:
time.sleep(conf.FirstVolumeRepeatPause)
firstLoop = False
else:
time.sleep(conf.NextVolumeRepeatPause)
class ToggleMuteAction(eg.ActionClass):
def __call__(self):
self.plugin.serialThread.SuspendReadEvents()
self.plugin.serialThread.Write('#1,11,' + str(int(not current.Mute)) + chr(13))
self.plugin.serialThread.ResumeReadEvents()
class CambridgeAudioSerial(eg.PluginClass):
def __init__(self):
self.serialThread = eg.SerialThread()
group = self
for cmd_name, cmd_text, cmd_cmd, cmd_rangespec in cmdList:
if cmd_text is None:
# New subgroup, or back up
if cmd_name is None:
group = self
else:
group = self.AddGroup(cmd_name)
if cmd_name == 'Volume': groupVolume = group
elif cmd_rangespec is not None:
# Command with argument
actionName, paramDescr = cmd_text.split('(')
actionName = actionName.strip()
paramDescr = paramDescr[:-1]
_cmdLeft, _cmdRight = cmd_cmd.split('x')
class Action(ValueAction):
name = actionName
cmd = cmd_cmd
parameterDescription = 'Value: (%s)' % paramDescr
cmdLeft = _cmdLeft
cmdRight = _cmdRight
Action.__name__ = cmd_name
group.AddAction(Action)
else:
# Argumentless command
class Action(CmdAction):
name = cmd_text
cmd = cmd_cmd
Action.__name__ = cmd_name
group.AddAction(Action)
group.AddAction(Raw)
class Action(VolumeAction):
name = 'Volume Up until event end'
increment = 1
Action.__name__ = 'VolumeUpUntilEnd'
groupVolume.AddAction(Action)
class Action(VolumeAction):
name = 'Volume Down until event end'
increment = -1
Action.__name__ = 'VolumeDownUntilEnd'
groupVolume.AddAction(Action)
class Action(ToggleMuteAction):
name = 'Toggle Mute'
Action.__name__ = 'ToggleMute'
groupVolume.AddAction(Action)
def __start__(self, port):
self.port = port
self.serialThread.parmre = re.compile('#(\d),(\d\d),(([^,]+)?(,(.*))?)??$')
self.serialThread.SetReadEventCallback(self.OnReceive)
self.serialThread.Open(port, 9600, '8N1')
self.serialThread.SetRts(0)
self.serialThread.Start()
current.Volume = 45
def __stop__(self):
self.serialThread.Close()
def Configure(self, port=0):
panel = eg.ConfigPanel(self)
portCtrl = panel.SerialPortChoice(port)
panel.AddLine('Port:', portCtrl)
while panel.Affirmed():
panel.SetResult(portCtrl.GetValue())
def OnReceive(self, serial):
buffer = ''
while True:
ch = serial.Read(1, 0.1)
if (ch == ''): return # nothing received inside timeout, possibly indicates erroneous data
if (ch != '\r'):
buffer += ch
continue
m = self.serialThread.parmre.match(buffer)
if (m is not None) and (m.group(1) in EventList) and (m.group(2) in EventList[m.group(1)]):
if (EventList[m.group(1)][m.group(2)] == 'VolumeChanged'):
current.Volume = int(m.group(3))
elif (EventList[m.group(1)][m.group(2)] == 'MuteStateChanged'):
current.Mute = bool(int(m.group(3)))
self.TriggerEvent(EventList[m.group(1)]['content'] + '.' + EventList[m.group(1)][m.group(2)], payload = m.group(3))
else:
self.TriggerEvent('Unknown(' + buffer + ')')
return-
cafe.racer
- Posts: 6
- Joined: Fri Dec 23, 2011 8:41 pm
Re: Serial Control Cambridge Audio 340R
Anyone? Please?
Anyway I could test the serial port?
Anyway I could test the serial port?
-
cafe.racer
- Posts: 6
- Joined: Fri Dec 23, 2011 8:41 pm
Re: Serial Control Cambridge Audio 340R
Thanks for that. Useful tool, but it didn't seem to help. Searching around for some help on com0com I found RealTerm, which also doesn't help me, but is useful in that it does exactly what EventGhost, the serial plugin, "my" plugin, the original Cambridge audio plugin do. Makes me think it's not the plugin code, but something else.
I will see about dragging another PC near the amp, see if that will work.
Another Question - my amp will reply with "#7,01,2" (Group 7 - replies from Source Commands, Command Number 1 - Input Select, Command Data 2 - Video 1 Selected) .
The original plugin would translate the first two "chunks", but I can't see a Command Reply of three chunks in that code, and I'm struggling to extend my plugin to translate the third chunk.
If I'm not making sense, currently my plugin has the event, I want it to have so I can DO something with those events.
I will see about dragging another PC near the amp, see if that will work.
Another Question - my amp will reply with "#7,01,2" (Group 7 - replies from Source Commands, Command Number 1 - Input Select, Command Data 2 - Video 1 Selected) .
The original plugin would translate the first two "chunks", but I can't see a Command Reply of three chunks in that code, and I'm struggling to extend my plugin to translate the third chunk.
If I'm not making sense, currently my plugin has the event
Code: Select all
CambridgeAudioSerial.Source.Input Select '02'Code: Select all
CambridgeAudioSerial.Source.Input Select.Video 1-
cafe.racer
- Posts: 6
- Joined: Fri Dec 23, 2011 8:41 pm
Re: Serial Control Cambridge Audio 340R
I tried a serial loopback test - nothing.
I tried shorting the jumpers 2 and 3 and a loopback - still nothing, so I bit the bullet and bought a USB - 2 x Serial cable, and now the commands work.
BUT reading from the port is random - it seems to drop characters
I tried shorting the jumpers 2 and 3 and a loopback - still nothing, so I bit the bullet and bought a USB - 2 x Serial cable, and now the commands work.
BUT reading from the port is random - it seems to drop characters