/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright 2013 - 2020, nymea GmbH * Contact: contact@nymea.io * * This file is part of nymea. * This project including source code and documentation is protected by * copyright law, and remains the property of nymea GmbH. All rights, including * reproduction, publication, editing and translation, are reserved. The use of * this project is subject to the terms of a license agreement to be concluded * with nymea GmbH in accordance with the terms of use of nymea GmbH, available * under https://nymea.io/license * * GNU Lesser General Public License Usage * Alternatively, this project may be redistributed and/or modified under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation; version 3. This project is distributed in the hope that * it will be useful, but WITHOUT ANY WARRANTY; without even the implied * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this project. If not, see . * * For any further details and any questions please contact us under * contact@nymea.io or see our FAQ/Licensing Information on * https://nymea.io/license/faq * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "bluos.h" #include "extern-plugininfo.h" #include #include #include #include BluOS::BluOS(NetworkAccessManager *networkmanager, QHostAddress hostAddress, int port, QObject *parent) : QObject(parent), m_hostAddress(hostAddress), m_port(port), m_networkManager(networkmanager) { } int BluOS::port() { return m_port; } QHostAddress BluOS::hostAddress() { return m_hostAddress; } QUuid BluOS::getStatus() { QUuid requestId = QUuid::createUuid(); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/Status"); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); QXmlStreamReader xml; xml.addData(reply->readAll()); if (xml.hasError()) { qCDebug(dcBluOS()) << "XML Error:" << xml.errorString(); } StatusResponse statusResponse; if (xml.readNextStartElement()) { if (xml.name() == "status") { while(xml.readNextStartElement()){ if(xml.name() == "artist"){ } else if(xml.name() == "artist"){ statusResponse.Artist = xml.readElementText(); } else if(xml.name() == "album"){ statusResponse.Album = xml.readElementText(); } else if(xml.name() == "name"){ statusResponse.Name = xml.readElementText(); } else if(xml.name() == "service"){ statusResponse.Service = xml.readElementText(); } else if(xml.name() == "serviceIcon"){ statusResponse.ServiceIcon = xml.readElementText(); } else if(xml.name() == "shuffle"){ statusResponse.Shuffle = xml.readElementText().toInt(); } else if(xml.name() == "repeat"){ statusResponse.Shuffle = xml.readElementText().toInt(); } else if(xml.name() == "state"){ statusResponse.PlaybackState = xml.readElementText().toInt(); } else if(xml.name() == "volume"){ statusResponse.Volume = xml.readElementText().toInt(); } else if(xml.name() == "mute"){ statusResponse.Mute = xml.readElementText().toInt(); } else { xml.skipCurrentElement(); } } } } emit statusReceived(statusResponse); }); return requestId; } QUuid BluOS::setVolume(uint volume) { QUuid requestId = QUuid::createUuid(); QUrlQuery query; query.addQueryItem("level", QString::number(volume)); query.addQueryItem("tell_slaves", "off"); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/Volume"); url.setQuery(query); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } emit actionExecuted(requestId, false); qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); QXmlStreamReader xml; xml.addData(reply->readAll()); if (xml.hasError()) { qCDebug(dcBluOS()) << "XML Error:" << xml.errorString(); } int volume = 0; bool mute = false; if (xml.readNextStartElement()) { if (xml.name() == "volume") { if(xml.attributes().hasAttribute("mute")) { mute = xml.attributes().value("mute").toInt(); } volume = xml.readElementText().toInt(); } } emit volumeReceived(volume, mute); emit actionExecuted(requestId, true); }); return requestId; } QUuid BluOS::setMute(bool mute) { QUuid requestId = QUuid::createUuid(); QUrlQuery query; query.addQueryItem("mute", QString::number(mute)); query.addQueryItem("tell_slaves", "off"); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/Volume"); url.setQuery(query); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } emit actionExecuted(requestId, false); qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); emit actionExecuted(requestId, true); }); return requestId; } QUuid BluOS::play() { return playBackControl(PlaybackCommand::Play); } QUuid BluOS::pause() { return playBackControl(PlaybackCommand::Pause); } QUuid BluOS::stop() { return playBackControl(PlaybackCommand::Stop); } QUuid BluOS::back() { return playBackControl(PlaybackCommand::Back); } QUuid BluOS::setShuffle(bool shuffle) { Q_UNUSED(shuffle) QUuid requestId = QUuid::createUuid(); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/Shuffle"); QUrlQuery query; query.addQueryItem("state", QString::number(shuffle)); url.setQuery(query); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } emit actionExecuted(requestId, false); qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); emit actionExecuted(requestId, true); }); return requestId; } QUuid BluOS::setRepeat(RepeatMode repeatMode) { Q_UNUSED(repeatMode) QUuid requestId = QUuid::createUuid(); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/Repeat"); QUrlQuery query; query.addQueryItem("state", QString::number(repeatMode)); url.setQuery(query); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } emit actionExecuted(requestId, false); qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); emit actionExecuted(requestId, true); }); return requestId; } QUuid BluOS::listPresets() { QUuid requestId = QUuid::createUuid(); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/Presets"); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); }); return requestId; } QUuid BluOS::loadPreset(int preset) { Q_UNUSED(preset) QUuid requestId = QUuid::createUuid(); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/Presets"); QUrlQuery query; query.addQueryItem("id", QString::number(preset)); url.setQuery(query); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); }); return requestId; } QUuid BluOS::addGroupPlayer(QHostAddress address, int port) { Q_UNUSED(address) Q_UNUSED(port) QUuid requestId = QUuid::createUuid(); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/AddSlave"); QUrlQuery query; query.addQueryItem("slave", address.toString()); query.addQueryItem("port", QString::number(port)); url.setQuery(query); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); }); return requestId; } QUuid BluOS::removeGroupPlayer(QHostAddress address, int port) { Q_UNUSED(address) Q_UNUSED(port) QUuid requestId = QUuid::createUuid(); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); url.setPath("/RemoveSlave"); QUrlQuery query; query.addQueryItem("slave", address.toString()); query.addQueryItem("port", QString::number(port)); url.setQuery(query); QNetworkReply *reply = m_networkManager->get(QNetworkRequest(url)); connect(reply, &QNetworkReply::finished, this, [reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); }); return requestId; } QUuid BluOS::skip() { return playBackControl(PlaybackCommand::Skip); } QUuid BluOS::playBackControl(BluOS::PlaybackCommand command) { QUuid requestId = QUuid::createUuid(); QUrl url; url.setScheme("http"); url.setHost(m_hostAddress.toString()); url.setPort(m_port); switch (command) { case PlaybackCommand::Play: url.setPath("/Play"); break; case PlaybackCommand::Pause: url.setPath("/Pause"); break; case PlaybackCommand::Stop: url.setPath("/Stop"); break; case PlaybackCommand::Back: url.setPath("/Back"); break; case PlaybackCommand::Skip: url.setPath("/Skip"); break; } QNetworkRequest request; request.setUrl(url); QNetworkReply *reply = m_networkManager->get(request); qCDebug(dcBluOS()) << "Sending request" << request.url(); connect(reply, &QNetworkReply::finished, this, [requestId, reply, this] { reply->deleteLater(); int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); // Check HTTP status code if (status != 200 || reply->error() != QNetworkReply::NoError) { if (reply->error() == QNetworkReply::HostNotFoundError) { emit connectionChanged(false); } emit actionExecuted(requestId, false); qCWarning(dcBluOS()) << "Request error:" << status << reply->errorString(); return; } emit connectionChanged(true); QXmlStreamReader xml; xml.addData(reply->readAll()); if (xml.hasError()) { qCDebug(dcBluOS()) << "XML Error:" << xml.errorString(); } emit actionExecuted(requestId, true); }); return requestId; }