/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Copyright (C) 2016-2018 Simon Stürz * * * * This file is part of nymea. * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library 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 library; If not, see * * . * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "devicepluginsenic.h" #include "devices/device.h" #include "plugininfo.h" #include "hardware/bluetoothlowenergy/bluetoothlowenergymanager.h" DevicePluginSenic::DevicePluginSenic() { } void DevicePluginSenic::init() { // Initialize plugin configurations m_autoSymbolMode = configValue(senicPluginAutoSymbolsParamTypeId).toBool(); } Device::DeviceError DevicePluginSenic::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms) { Q_UNUSED(params) if (deviceClassId != nuimoDeviceClassId) return Device::DeviceErrorDeviceClassNotFound; if (!hardwareManager()->bluetoothLowEnergyManager()->available()) return Device::DeviceErrorHardwareNotAvailable; if (!hardwareManager()->bluetoothLowEnergyManager()->enabled()) return Device::DeviceErrorHardwareNotAvailable; BluetoothDiscoveryReply *reply = hardwareManager()->bluetoothLowEnergyManager()->discoverDevices(); connect(reply, &BluetoothDiscoveryReply::finished, this, &DevicePluginSenic::onBluetoothDiscoveryFinished); return Device::DeviceErrorAsync; } Device::DeviceSetupStatus DevicePluginSenic::setupDevice(Device *device) { if (!m_reconnectTimer) { m_reconnectTimer = hardwareManager()->pluginTimerManager()->registerTimer(10); connect(m_reconnectTimer, &PluginTimer::timeout, this, &DevicePluginSenic::onReconnectTimeout); } qCDebug(dcSenic()) << "Setup device" << device->name() << device->params(); QBluetoothAddress address = QBluetoothAddress(device->paramValue(nuimoDeviceMacParamTypeId).toString()); QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(address, device->name(), 0); BluetoothLowEnergyDevice *bluetoothDevice = hardwareManager()->bluetoothLowEnergyManager()->registerDevice(deviceInfo, QLowEnergyController::RandomAddress); Nuimo *nuimo = new Nuimo(device, bluetoothDevice, this); connect(nuimo, &Nuimo::buttonPressed, this, &DevicePluginSenic::onButtonPressed); connect(nuimo, &Nuimo::buttonReleased, this, &DevicePluginSenic::onButtonReleased); connect(nuimo, &Nuimo::swipeDetected, this, &DevicePluginSenic::onSwipeDetected); connect(nuimo, &Nuimo::rotationValueChanged, this, &DevicePluginSenic::onRotationValueChanged); m_nuimos.insert(nuimo, device); nuimo->bluetoothDevice()->connectDevice(); return Device::DeviceSetupStatusSuccess; } Device::DeviceError DevicePluginSenic::executeAction(Device *device, const Action &action) { QPointer nuimo = m_nuimos.key(device); if (nuimo.isNull()) return Device::DeviceErrorHardwareFailure; if (!nuimo->bluetoothDevice()->connected()) { return Device::DeviceErrorHardwareNotAvailable; } if (action.actionTypeId() == nuimoShowLogoActionTypeId) { if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Up") nuimo->showImage(Nuimo::MatrixTypeUp); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Down") nuimo->showImage(Nuimo::MatrixTypeDown); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Left") nuimo->showImage(Nuimo::MatrixTypeLeft); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Right") nuimo->showImage(Nuimo::MatrixTypeRight); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Play") nuimo->showImage(Nuimo::MatrixTypePlay); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Pause") nuimo->showImage(Nuimo::MatrixTypePause); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Stop") nuimo->showImage(Nuimo::MatrixTypeStop); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Music") nuimo->showImage(Nuimo::MatrixTypeMusic); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Heart") nuimo->showImage(Nuimo::MatrixTypeHeart); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Next") nuimo->showImage(Nuimo::MatrixTypeNext); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Previous") nuimo->showImage(Nuimo::MatrixTypePrevious); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Circle") nuimo->showImage(Nuimo::MatrixTypeCircle); if (action.param(nuimoShowLogoActionLogoParamTypeId).value().toString() == "Light") nuimo->showImage(Nuimo::MatrixTypeLight); return Device::DeviceErrorNoError; } return Device::DeviceErrorActionTypeNotFound; } void DevicePluginSenic::deviceRemoved(Device *device) { if (!m_nuimos.values().contains(device)) return; Nuimo *nuimo = m_nuimos.key(device); m_nuimos.take(nuimo); delete nuimo; if (myDevices().isEmpty()) { hardwareManager()->pluginTimerManager()->unregisterTimer(m_reconnectTimer); m_reconnectTimer = nullptr; } } void DevicePluginSenic::onReconnectTimeout() { foreach (Nuimo *nuimo, m_nuimos.keys()) { if (!nuimo->bluetoothDevice()->connected()) { nuimo->bluetoothDevice()->connectDevice(); } } } void DevicePluginSenic::onBluetoothDiscoveryFinished() { BluetoothDiscoveryReply *reply = static_cast(sender()); if (reply->error() != BluetoothDiscoveryReply::BluetoothDiscoveryReplyErrorNoError) { qCWarning(dcSenic()) << "Bluetooth discovery error:" << reply->error(); reply->deleteLater(); emit devicesDiscovered(nuimoDeviceClassId, QList()); return; } QList deviceDescriptors; foreach (const QBluetoothDeviceInfo &deviceInfo, reply->discoveredDevices()) { if (deviceInfo.name().contains("Nuimo")) { DeviceDescriptor descriptor(nuimoDeviceClassId, "Nuimo", deviceInfo.name() + " (" + deviceInfo.address().toString() + ")"); ParamList params; foreach (Device *existingDevice, myDevices()) { if (existingDevice->paramValue(nuimoDeviceMacParamTypeId).toString() == deviceInfo.address().toString()) { descriptor.setDeviceId(existingDevice->id()); break; } } params.append(Param(nuimoDeviceMacParamTypeId, deviceInfo.address().toString())); descriptor.setParams(params); deviceDescriptors.append(descriptor); } } reply->deleteLater(); emit devicesDiscovered(nuimoDeviceClassId, deviceDescriptors); } void DevicePluginSenic::onButtonPressed() { Nuimo *nuimo = static_cast(sender()); Device *device = m_nuimos.value(nuimo); emitEvent(Event(nuimoPressedEventTypeId, device->id(), ParamList() << Param(nuimoPressedEventButtonNameParamTypeId, "•"))); if(m_autoSymbolMode) { nuimo->showImage(Nuimo::MatrixType::MatrixTypeCircle); } } void DevicePluginSenic::onButtonReleased() { // TODO: user timer for detekt long pressed (if needed) } void DevicePluginSenic::onSwipeDetected(const Nuimo::SwipeDirection &direction) { Nuimo *nuimo = static_cast(sender()); Device *device = m_nuimos.value(nuimo); switch (direction) { case Nuimo::SwipeDirectionLeft: emitEvent(Event(nuimoPressedEventTypeId, device->id(), ParamList() << Param(nuimoPressedEventButtonNameParamTypeId, "←"))); break; case Nuimo::SwipeDirectionRight: emitEvent(Event(nuimoPressedEventTypeId, device->id(), ParamList() << Param(nuimoPressedEventButtonNameParamTypeId, "→"))); break; case Nuimo::SwipeDirectionUp: emitEvent(Event(nuimoPressedEventTypeId, device->id(), ParamList() << Param(nuimoPressedEventButtonNameParamTypeId, "↑"))); break; case Nuimo::SwipeDirectionDown: emitEvent(Event(nuimoPressedEventTypeId, device->id(), ParamList() << Param(nuimoPressedEventButtonNameParamTypeId, "↓"))); break; } if (m_autoSymbolMode) { switch (direction) { case Nuimo::SwipeDirectionLeft: nuimo->showImage(Nuimo::MatrixType::MatrixTypeLeft); break; case Nuimo::SwipeDirectionRight: nuimo->showImage(Nuimo::MatrixType::MatrixTypeRight); break; case Nuimo::SwipeDirectionUp: nuimo->showImage(Nuimo::MatrixType::MatrixTypeUp); break; case Nuimo::SwipeDirectionDown: nuimo->showImage(Nuimo::MatrixType::MatrixTypeDown); break; } } } void DevicePluginSenic::onRotationValueChanged(const uint &value) { Nuimo *nuimo = static_cast(sender()); Device *device = m_nuimos.value(nuimo); device->setStateValue(nuimoRotationStateTypeId, value); } void DevicePluginSenic::onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value) { qCDebug(dcSenic()) << "Plugin configuration changed"; // Check auto symbol mode if (paramTypeId == senicPluginAutoSymbolsParamTypeId) { qCDebug(dcSenic()) << "Auto symbol mode" << (value.toBool() ? "enabled." : "disabled."); m_autoSymbolMode = value.toBool(); } }