2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.volumio.internal.mapping;
15 import java.io.ByteArrayOutputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
19 import java.net.URLConnection;
20 import java.util.Objects;
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.json.JSONException;
25 import org.json.JSONObject;
26 import org.openhab.binding.volumio.internal.VolumioBindingConstants;
27 import org.openhab.core.library.types.OnOffType;
28 import org.openhab.core.library.types.PercentType;
29 import org.openhab.core.library.types.PlayPauseType;
30 import org.openhab.core.library.types.RawType;
31 import org.openhab.core.library.types.StringType;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
36 * The {@link VolumioData} class defines state data of volumio.
38 * @author Patrick Sernetz - Initial Contribution
39 * @author Chris Wohlbrecht - Adaption for openHAB 3
40 * @author Michael Loercher - Adaption for openHAB 3
43 public class VolumioData {
45 private final Logger logger = LoggerFactory.getLogger(VolumioData.class);
47 private String title = "";
48 private boolean titleDirty;
50 private String album = "";
51 private boolean albumDirty;
53 private String artist = "";
54 private boolean artistDirty;
56 private int volume = 0;
57 private boolean volumeDirty;
59 private String state = "";
60 private boolean stateDirty;
62 private String trackType = "";
63 private boolean trackTypeDirty;
65 private String position = "";
66 private boolean positionDirty;
68 private byte @Nullable [] coverArt = null;
69 private String coverArtUrl = "";
70 private boolean coverArtDirty;
72 private boolean repeat = false;
73 private boolean repeatDirty;
75 private boolean random = false;
76 private boolean randomDirty;
78 public void update(JSONObject jsonObject) throws JSONException {
79 if (jsonObject.has(VolumioBindingConstants.CHANNEL_TITLE)) {
80 setTitle(jsonObject.getString(VolumioBindingConstants.CHANNEL_TITLE));
85 if (jsonObject.has(VolumioBindingConstants.CHANNEL_ALBUM)
86 && !jsonObject.isNull(VolumioBindingConstants.CHANNEL_ALBUM)) {
87 setAlbum(jsonObject.getString(VolumioBindingConstants.CHANNEL_ALBUM));
92 if (jsonObject.has(VolumioBindingConstants.CHANNEL_VOLUME)) {
93 setVolume(jsonObject.getInt(VolumioBindingConstants.CHANNEL_VOLUME));
98 if (jsonObject.has(VolumioBindingConstants.CHANNEL_ARTIST)) {
99 setArtist(jsonObject.getString(VolumioBindingConstants.CHANNEL_ARTIST));
105 if (jsonObject.has("status")) {
106 setState(jsonObject.getString("status"));
111 if (jsonObject.has(VolumioBindingConstants.CHANNEL_TRACK_TYPE)) {
112 setTrackType(jsonObject.getString(VolumioBindingConstants.CHANNEL_TRACK_TYPE));
117 if (jsonObject.has(VolumioBindingConstants.CHANNEL_COVER_ART)
118 && !jsonObject.isNull(VolumioBindingConstants.CHANNEL_COVER_ART)) {
119 setCoverArt(jsonObject.getString(VolumioBindingConstants.CHANNEL_COVER_ART));
124 if (jsonObject.has(VolumioBindingConstants.CHANNEL_PLAY_RANDOM)
125 && !jsonObject.isNull(VolumioBindingConstants.CHANNEL_PLAY_RANDOM)) {
126 setRandom(jsonObject.getBoolean(VolumioBindingConstants.CHANNEL_PLAY_RANDOM));
131 if (jsonObject.has(VolumioBindingConstants.CHANNEL_PLAY_REPEAT)
132 && !jsonObject.isNull(VolumioBindingConstants.CHANNEL_PLAY_REPEAT)) {
133 setRepeat(jsonObject.getBoolean(VolumioBindingConstants.CHANNEL_PLAY_REPEAT));
139 public StringType getTitle() {
140 return new StringType(title);
143 public void setTitle(String title) {
144 if (!title.equals(this.title)) {
146 this.titleDirty = true;
148 this.titleDirty = false;
152 public StringType getAlbum() {
153 return new StringType(album);
156 public void setAlbum(String album) {
157 if ("null".equals(album)) {
161 if (!album.equals(this.album)) {
163 this.albumDirty = true;
165 this.albumDirty = false;
169 public StringType getArtist() {
170 return new StringType(artist);
173 public void setArtist(String artist) {
174 if ("null".equals(artist)) {
178 if (!artist.equals(this.artist)) {
179 this.artist = artist;
180 this.artistDirty = true;
182 this.artistDirty = false;
186 public PercentType getVolume() {
187 return new PercentType(volume);
190 public void setVolume(int volume) {
191 if (volume != this.volume) {
192 this.volume = volume;
193 this.volumeDirty = true;
195 this.volumeDirty = false;
199 public void setState(String state) {
200 if (!state.equals(this.state)) {
202 this.stateDirty = true;
204 this.stateDirty = false;
208 public PlayPauseType getState() {
209 PlayPauseType playPauseStatus;
211 if ("play".equals(state)) {
212 playPauseStatus = PlayPauseType.PLAY;
214 playPauseStatus = PlayPauseType.PAUSE;
217 return playPauseStatus;
220 public void setTrackType(String trackType) {
221 if (!trackType.equals(this.trackType)) {
222 this.trackType = trackType;
223 this.trackTypeDirty = true;
225 this.trackTypeDirty = false;
229 public StringType getTrackType() {
230 return new StringType(trackType);
233 public void setPosition(String position) {
234 if (!position.equals(this.position)) {
235 this.position = position;
236 this.positionDirty = true;
238 this.positionDirty = false;
242 public void setCoverArt(@Nullable String coverArtUrl) {
243 if (coverArtUrl != null) {
244 if (!Objects.equals(coverArtUrl, this.coverArtUrl)) {
245 if (!coverArtUrl.startsWith("http")) {
250 URL url = new URL(coverArtUrl);
251 URLConnection connection = url.openConnection();
252 InputStream inStream = null;
253 inStream = connection.getInputStream();
254 coverArt = inputStreamToByte(inStream);
255 } catch (IOException ioe) {
258 this.coverArtDirty = true;
260 this.coverArtDirty = false;
267 private byte @Nullable [] inputStreamToByte(InputStream is) {
268 byte @Nullable [] imgdata = null;
269 try (ByteArrayOutputStream bytestream = new ByteArrayOutputStream()) {
271 while ((ch = is.read()) != -1) {
272 bytestream.write(ch);
274 imgdata = bytestream.toByteArray();
276 } catch (Exception e) {
277 logger.error("Could not open or read input stream {}", e.getMessage());
283 public @Nullable RawType getCoverArt() {
284 byte[] localCoverArt = coverArt;
285 return localCoverArt == null ? null : new RawType(localCoverArt, "image/jpeg");
288 public OnOffType getRandom() {
289 return OnOffType.from(random);
292 public void setRandom(boolean val) {
293 if (val != this.random) {
295 this.randomDirty = true;
297 this.randomDirty = false;
301 public OnOffType getRepeat() {
302 return OnOffType.from(repeat);
305 public void setRepeat(boolean val) {
306 if (val != this.repeat) {
308 this.repeatDirty = true;
310 this.repeatDirty = false;
314 public StringType getPosition() {
315 return new StringType(position);
318 public boolean isPositionDirty() {
319 return positionDirty;
322 public boolean isStateDirty() {
326 public boolean isTitleDirty() {
330 public boolean isAlbumDirty() {
334 public boolean isArtistDirty() {
338 public boolean isVolumeDirty() {
342 public boolean isTrackTypeDirty() {
343 return trackTypeDirty;
346 public boolean isCoverArtDirty() {
347 return coverArtDirty;
350 public boolean isRandomDirty() {
354 public boolean isRepeatDirty() {