Skip to content

Commit 04d659e

Browse files
committed
moved code to __init__.py
1 parent 5fd0e76 commit 04d659e

File tree

2 files changed

+230
-231
lines changed

2 files changed

+230
-231
lines changed

fsapi/__init__.py

Lines changed: 230 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,230 @@
1-
__author__ = 'zhelev'
1+
"""
2+
Support for interaction with Frontier Silicon Devices (Medion, Hama, Auna,...) devices.
3+
"""
4+
import requests
5+
from lxml import objectify
6+
7+
class FSAPI(object):
8+
9+
PLAY_STATES = {
10+
0: 'stopped',
11+
1: 'unknown',
12+
2: 'playing',
13+
3: 'paused',
14+
}
15+
16+
def __init__(self, fsapi_device_url, pin):
17+
self.pin = pin
18+
self.sid = None
19+
self.webfsapi = None
20+
self.fsapi_device_url = fsapi_device_url
21+
22+
self.webfsapi = self.get_fsapi_endpoint()
23+
self.sid = self.create_session()
24+
25+
def get_fsapi_endpoint(self):
26+
r = requests.get(self.fsapi_device_url)
27+
doc = objectify.fromstring(r.content)
28+
return doc.webfsapi.text
29+
30+
def create_session(self):
31+
doc = self.call('CREATE_SESSION')
32+
return doc.sessionId.text
33+
34+
def call(self, path, extra=None):
35+
if not self.webfsapi:
36+
raise Exception('No server found')
37+
38+
if type(extra) is not dict:
39+
extra = dict()
40+
41+
params = dict(
42+
pin=self.pin,
43+
sid=self.sid,
44+
)
45+
46+
params.update(**extra)
47+
48+
r = requests.get('%s/%s' % (self.webfsapi, path), params=params)
49+
if r.status_code == 404:
50+
return None
51+
52+
return objectify.fromstring(r.content)
53+
54+
def __del__(self):
55+
self.call('DELETE_SESSION')
56+
57+
### Handlers
58+
59+
def handle_get(self, item):
60+
return self.call('GET/{}'.format(item))
61+
62+
def handle_set(self, item, value):
63+
doc = self.call('SET/{}'.format(item), dict(value=value))
64+
if doc is None:
65+
return None
66+
67+
return doc.status == 'FS_OK'
68+
69+
def handle_text(self, item):
70+
doc = self.handle_get(item)
71+
if doc is None:
72+
return None
73+
74+
return doc.value.c8_array.text or None
75+
76+
def handle_int(self, item):
77+
doc = self.handle_get(item)
78+
if doc is None:
79+
return None
80+
81+
return int(doc.value.u8.text) or None
82+
83+
# returns an int, assuming the value does not exceed 8 bits
84+
def handle_long(self, item):
85+
doc = self.handle_get(item)
86+
if doc is None:
87+
return None
88+
89+
return int(doc.value.u32.text) or None
90+
91+
def handle_list(self, item):
92+
doc = self.call('LIST_GET_NEXT/'+item+'/-1', dict(
93+
maxItems=100,
94+
))
95+
96+
if doc is None:
97+
return []
98+
99+
if not doc.status == 'FS_OK':
100+
return []
101+
102+
ret = list()
103+
for index, item in enumerate(list(doc.iterchildren('item'))):
104+
temp = dict(band=index)
105+
for field in list(item.iterchildren()):
106+
temp[field.get('name')] = list(field.iterchildren()).pop()
107+
ret.append(temp)
108+
109+
return ret
110+
111+
def collect_labels(self, items):
112+
if items is None:
113+
return []
114+
115+
return [ str(item['label']) for item in items if item['label'] ]
116+
117+
### Properties
118+
@property
119+
def play_status(self):
120+
status = self.handle_int('netRemote.play.status')
121+
return self.PLAY_STATES.get(status)
122+
123+
@property
124+
def play_info_name(self):
125+
return self.handle_text('netRemote.play.info.name')
126+
127+
@property
128+
def play_info_text(self):
129+
return self.handle_text('netRemote.play.info.text')
130+
131+
@property
132+
def play_info_artist(self):
133+
return self.handle_text('netRemote.play.info.artist')
134+
135+
@property
136+
def play_info_album(self):
137+
return self.handle_text('netRemote.play.info.album')
138+
139+
@property
140+
def play_info_graphics(self):
141+
return self.handle_text('netRemote.play.info.graphicUri')
142+
143+
@property
144+
def volume_steps(self):
145+
return self.handle_int('netRemote.sys.caps.volumeSteps')
146+
147+
### Read-write
148+
149+
#1=Play; 2=Pause; 3=Next (song/station); 4=Previous (song/station)
150+
def play_control(self, value):
151+
return self.handle_set('netRemote.play.control', value)
152+
153+
def play(self):
154+
return self.play_control(1)
155+
156+
def pause(self):
157+
return self.play_control(2)
158+
159+
def next(self):
160+
return self.play_control(3)
161+
162+
def prev(self):
163+
return self.play_control(4)
164+
165+
# Volume
166+
def get_volume(self):
167+
return self.handle_int('netRemote.sys.audio.volume')
168+
169+
def set_volume(self, value):
170+
return self.handle_set('netRemote.sys.audio.volume', value)
171+
172+
volume = property(get_volume, set_volume)
173+
174+
# Frienldy name
175+
def get_friendly_name(self):
176+
return self.handle_text('netRemote.sys.info.friendlyName')
177+
178+
def set_friendly_name(self, value):
179+
return self.handle_set('netRemote.sys.info.friendlyName', value)
180+
181+
friendly_name = property(get_friendly_name, set_friendly_name)
182+
183+
# Mute
184+
def get_mute(self):
185+
return bool(self.handle_int('netRemote.sys.audio.mute'))
186+
187+
def set_mute(self, value=False):
188+
return self.handle_set('netRemote.sys.audio.mute', int(value))
189+
190+
mute = property(get_mute, set_mute)
191+
192+
# Power
193+
def get_power(self):
194+
return bool(self.handle_int('netRemote.sys.power'))
195+
196+
def set_power(self, value=False):
197+
return self.handle_set('netRemote.sys.power', int(value))
198+
199+
power = property(get_power, set_power)
200+
201+
# Modes
202+
@property
203+
def modes(self):
204+
return self.handle_list('netRemote.sys.caps.validModes')
205+
206+
@property
207+
def mode_list(self):
208+
return self.collect_labels(self.modes)
209+
210+
def get_mode(self):
211+
m = None
212+
intMode = self.handle_long('netRemote.sys.mode')
213+
for mo in self.modes:
214+
if mo['band'] == intMode:
215+
m = mo['label']
216+
return m
217+
218+
def set_mode(self, value):
219+
m = -1
220+
for mo in self.modes:
221+
if mo['label'] == value:
222+
m = mo['band']
223+
224+
self.handle_set('netRemote.sys.mode', m)
225+
226+
mode = property(get_mode, set_mode)
227+
228+
@property
229+
def duration(self):
230+
return self.handle_long('netRemote.play.info.duration')

0 commit comments

Comments
 (0)