Skip to content

Commit

Permalink
Merge PR #494: WIP: New Plugin: nymea owlets
Browse files Browse the repository at this point in the history
  • Loading branch information
jenkins committed Nov 19, 2024
2 parents a35312b + 8eeeeb1 commit d6d0870
Show file tree
Hide file tree
Showing 29 changed files with 7,032 additions and 0 deletions.
12 changes: 12 additions & 0 deletions debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,18 @@ Description: nymea integration plugin for osdomotics
This package contains the nymea integration plugin for osdomotics.


Package: nymea-plugin-owlet
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
avrdude,
nymea-plugins-translations,
Description: nymea.io plugin for nymea:owlet
nymea:owlet is a firmware for microcontrollers (Arduino/ESP8266/ESP32) which
exposes pins of the microcontroller to nymea and allows using them for
whatever purpose like moodlights, control relays, inputs etc.


Package: nymea-plugin-philipshue
Architecture: any
Depends: ${shlibs:Depends},
Expand Down
2 changes: 2 additions & 0 deletions debian/nymea-plugin-owlet.install.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginowlet.so
owlet/firmware usr/share/nymea/owlet/firmware
1 change: 1 addition & 0 deletions nymea-plugins.pro
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ PLUGIN_DIRS = \
openuv \
openweathermap \
osdomotics \
owlet \
philipshue \
powerfox \
pushbullet \
Expand Down
84 changes: 84 additions & 0 deletions owlet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Owlet

nymea:owlet is a firmware for different microcontrollers (Arduino/ESP8266/ESP32) which
exposes pins of the microcontroller to nymea and allows using them for
whatever purpose like moodlights, control relays, reading analog values
or controlling servos.

# ESP8285

# ESP32

# M5Stick-C


# Arduino

In order to use owlet with an [Arduino](https://docs.arduino.cc/) you need to add the corresponding model into nymea. Once the thing is connected the firmware will be flashed automatically if required.

Following models are available:

* [Arduino Uno](https://docs.arduino.cc/hardware/uno-rev3)
* [Arduino Mini Pro (5v, 16MHz)](https://docs.arduino.cc/retired/boards/arduino-pro-mini)
* [Arduino Mini Pro (3.3v, 8MHz)](https://docs.arduino.cc/retired/boards/arduino-pro-mini)
* [Arduino Nano](https://store.arduino.cc/products/arduino-nano)

Once the Arduino has been added to nymea and the owlet firmware has been flashed successfully, the pins
can be configured as desired within the Arduino thing settings. Depending on the pin capabilities you can select
how the mode for each pin you require for your project. By default all pins are unconfigured.

When applying the settings, for each pin a new thing will appear in nymea giving you controls and information about
the current states of the pin. If a pin has been configured to a specific type and you want to remove a thing,
just configure it as type `None` and the associated thing will be removed from nymea.


## Available configurations

Not all pins can be configured to any type. Within the settings you can see for each pin
the possible configurations.

### Digital Output

If you configure a pin as *Output* you can switch on and off the associated GPIO.

Usecase examples:

* Switching relays
* Enable / Disable a LED

### Digital Input

If you configure a pin as *Input* you get a thing with a `bool` state indicating if the current state of the pin.

Usecase examples:

* Buttons
* Contact sensors

### Analog output (PWM)

If you configure a pin as *PWM* you can set the current duty cylcle of the PWM in a range of 0 - 255. The frequency of the duty cycle depends on the hardware you are using and requires some datasheet reading in order to understand hot it works.

[Arduino analogWrite() refference](https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/
)

Usecase examples:

* LED brightness
* Piezo buzzer
* Control motor speed

### Analog input (ADC)

If you configure a pin as *Analog input* you can read periodically the value from the internal ADC (analog digital converter). Most ADCs have a resolution of 10 Bits giving you a value range of 0 - 1023. Once you configured the pin as analog input you can configure in the thing settings how often the value should be fetched. Default is every 500 ms.

Usecase examples:

* Reading analog sensor values like humidity, distance...
* Reading a potentiometer value

### Servo

If you configure a pin as *Servo* you can control a servo motor in the range of 0° - 180°. A servo normally gets controlled using a PWM signal, but for most DIY servos the internal PWM functionality has a to high frequency. This mode makes use of the [Arduino Servo library](https://www.arduino.cc/reference/en/libraries/servo/) and uses the internal timers to generate a customizable PWM signal.

> Please note that if you configure a Servo, 2 internal timers will be used and therefore you loose some native PWM functionality. Plase read the documetation of your Hardware.
100 changes: 100 additions & 0 deletions owlet/arduinoflasher.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "arduinoflasher.h"
#include "extern-plugininfo.h"

#include <QDir>
#include <QJsonDocument>

ArduinoFlasher::ArduinoFlasher(Arduino model, const QString &serialPort, QObject *parent) :
QObject(parent),
m_model(model),
m_serialPort(serialPort)
{
QString firmwareBasePath = "usr/share/nymea/owlet/firmware";

switch (model) {
case ArduinoUno: {
QString firmwarePath = firmwareBasePath + QDir::separator() + "arduino-uno";
QVariantMap releaseInfo = loadReleaseInfo(firmwarePath);
if (releaseInfo.isEmpty())
return;

m_availableVersion = releaseInfo.value("version").toString();
m_firmwareFileName = firmwarePath + QDir::separator() + releaseInfo.value("firmwareFile").toString();

if (!QFileInfo::exists(m_firmwareFileName)) {
qCWarning(dcOwlet()) << "ArduinoFlasher: Could not find the firmware file for flashing" << m_firmwareFileName;
return;
}

m_flashProcessArguments << "-c" << "avrisp" << "-p" << "m328p" << "-P" << serialPort << "-b" << "19200" << "-U" << QString("flash:w:%1:i").arg(m_firmwareFileName);
m_available = true;
break;
}
case ArduinoNano: {
break;
}
case ArduinoMiniPro3V: {
break;
}
case ArduinoMiniPro5V: {
break;
}
}
}

QString ArduinoFlasher::availableVersion() const
{
return m_availableVersion;
}

bool ArduinoFlasher::flashFirmware()
{
if (!m_available)
return false;

if (m_flashProcess)
return false;

m_flashProcess = new QProcess(this);
m_flashProcess->setProgram("avrdude");
m_flashProcess->setArguments(m_flashProcessArguments);
connect(m_flashProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onProcessFinished(int,QProcess::ExitStatus)));
m_flashProcess->start();

return true;
}

QVariantMap ArduinoFlasher::loadReleaseInfo(const QString &firmwareDirectoryPath)
{
QFileInfo releaseFileInfo(firmwareDirectoryPath + QDir::separator() + "release.json");
if (!releaseFileInfo.exists()) {
qCWarning(dcOwlet()) << "ArduinoFlasher: Could not load release info. The release file does not exist" << releaseFileInfo.absoluteFilePath();
return QVariantMap();
}

QFile releaseFile;
releaseFile.setFileName(releaseFileInfo.absoluteFilePath());
if (!releaseFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
qCWarning(dcOwlet()) << "ArduinoFlasher: Could not open release file" << releaseFileInfo.absoluteFilePath();
return QVariantMap();
}

QByteArray releaseJsonData = releaseFile.readAll();
releaseFile.close();

return QJsonDocument::fromJson(releaseJsonData).toVariant().toMap();
}

void ArduinoFlasher::onProcessFinished(int returnCode, QProcess::ExitStatus exitStatus)
{
if (returnCode != EXIT_SUCCESS || exitStatus != QProcess::NormalExit) {
qCWarning(dcOwlet()) << "ArduinoFlasher: Flash process finished with error" << returnCode << exitStatus;
emit flashProcessFinished(false);
} else {
qCDebug(dcOwlet()) << "ArduinoFlasher: Flash process finished successfully";
emit flashProcessFinished(true);
}

m_flashProcess->deleteLater();
m_flashProcess = nullptr;
}
49 changes: 49 additions & 0 deletions owlet/arduinoflasher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef ARDUINOFLASHER_H
#define ARDUINOFLASHER_H

#include <QObject>
#include <QFileInfo>
#include <QProcess>

class ArduinoFlasher : public QObject
{
Q_OBJECT
public:
enum Arduino {
ArduinoUno,
ArduinoMiniPro5V,
ArduinoMiniPro3V,
ArduinoNano
};
Q_ENUM(Arduino)

explicit ArduinoFlasher(Arduino model, const QString &serialPort, QObject *parent = nullptr);

bool available() const;

QString availableVersion() const;

bool flashFirmware();

signals:
void flashProcessFinished(bool success);

private:
Arduino m_model = ArduinoUno;
QString m_serialPort;

QProcess *m_flashProcess = nullptr;
bool m_available = false;
QString m_availableVersion;
QString m_firmwareFileName;

QStringList m_flashProcessArguments;

QVariantMap loadReleaseInfo(const QString &firmwareDirectoryPath);

private slots:
void onProcessFinished(int returnCode, QProcess::ExitStatus exitStatus);

};

#endif // ARDUINOFLASHER_H
Loading

0 comments on commit d6d0870

Please sign in to comment.