Image docker available here !
I disagree
Many v3 users have used Arduino for cost reasons mainly, followed my tutorials to the letter without understanding everything, and were happy to have just a piece of code to upload to the Arduino!
Nice!
@billona So for now, what does the Arduino service manage?
Is 433MHz transmission/reception functional?
Currently nothing at all
For now, I’m working on the front-end.
I’m formatting the devices, but I still have a few issues. I can’t make my API POST request to save the device in the DB.
I know my code contains errors. Even though I’m improving more and more, I’m still in the learning phase of Preact. Once the front-end works correctly, I’ll take care of the back-end. First things first:
- A js to send data to the Arduino
- Improving the Arduino API.
Additionally, I took the liberty of making a few small changes:
- I added the manufacturer parameter in the USB API to automate the connection of the Arduino in the future
- I made a small addition to the device model to add Arduino sub-services (433 Emission, 433 Chacon Emission, IR Emission, …), as well as a data pin field to define where to send the information
- I translated the Arduino service into French.
If you have any feedback regarding my code, don’t hesitate ![]()
Could we discuss that? I think that’s the real question! ![]()
Edit: Going back, I found your post, sorry I didn’t see the message before given the wave of messages here, I’m putting it back:
The story of the sub-service I’m not convinced. Could you explain here what your operation is? How does it work for the user?
And what is this code story?
The definition of the API is the most important thing. Because once the API is defined, we will not be able to modify it until the next major version of Gladys, as users will depend on this API. We want to be 100% sure that this API does the job for the long term.
Mmm why can’t you store the Arduino in the form of a device? one Arduino = one device. You can use the comPath as an identifier, and at startup go get the Arduino(s).
For now, you can code the UI to only support one Arduino for now if you don’t want to bother too much and release a v0.1 quite quickly, but in terms of storage I would see it more in the devices than in the variables ![]()
As I’ve tinkered a lot with the 433 modules, I used these ones
Hi. Good while waiting for it to work…
My experience:
For the SEND part:
You need, as a variable, the number of times the code must be sent: sometimes it’s too much, sometimes it’s not enough. Example if I send the code 433 4 times, the code is not received by my device 100% of the time (due to temporary interference or background noise), if I put 15 times, my alarm rings 2 times it has time to read the code 2 times, it’s too much. It could turn on and off a device in one send.
RECEIVER:
Another thing for the receiver: sometimes the RF433 code is not retrieved correctly. Gladys interprets the code sent by the Arduino and creates a device with a crappy code (like « E53F »).
We can limit this by cutting the too short sequences, it avoids the number of false devices but, same thing, we must keep the possibility to provide for a dialogue with a short code. So eventually to be parameterized in the setup.
Another proposal: you can put the Arduino in learning mode (one code = one device created) then you cut it (an unknown code received well it does nothing).
More generally, all the variables used in the Arduino code could be reported in the SETUP of the module to be able to customize everything. As I told you on the phone, for the big newbie like me who does not want to spend 1000 years defining all the variables, a « not stupid » variable must be put by default. Even you can put a button « advanced » that reveals the values that usually we do not fiddle with for the experienced user.
From the user’s perspective, I envisioned something like this:
The user chooses how they want the device to function, provides the data pin and the message. Then, in terms of code, we would have this:
This allows storing a parameter in the DB, which will correspond to the function that will be called in the Arduino.
Example:
- Sub-service: emit_ir
- Data pin: 3
- Code: 0xF7C03F
I saw some complications regarding that. But I think we’re getting a bit confused about our definitions of devices, so here’s what I had in mind:
One Arduino connected via USB, its path and model in the variables. Then, each device will allow performing an action on this board.
Initially, I didn’t find a simple way to manage 2 Arduinos in the DB, but in the end, if we do it a bit like the Serial module of Gladys 3, it can work ![]()
I’ll look into modifying that. ![]()
For me, the data pin does not change every time. In the setup at connection, that would suffice, like the number of repetitions. However, protocol, pulselength change according to the device.
Well, after some work… The Arduinos are now implemented as devices ![]()
Here’s how it looks for now:
Well, for now the UI is quite basic, I admit
But it is functional. I intend to improve the rendering once everything works as I wish.
As for the DB, here’s what it looks like:
@pierre-gilles to explain a bit about my initial idea, I first based myself on the DB model available in the API documentation. However, this model does not mention the t_device_param table, the same table used by RTSP cameras to store URLs. So I modified everything so that each property of the Arduino (comPath, model) is stored there.
Now that the Arduinos are stored without any difficulties (and especially now that I have managed to familiarize myself with the creation of devices via the front
), I will look into creating other « types » of devices. For me, these would be linked to an Arduino, and would contain the aforementioned properties:
- A sub-service to specify the role (433 transmission, 433 reception, IR transmission, …)
- A data pin to know where the data transits on the Arduino,
- Possible codes concerning the transmission.
So I’m thinking about all that during the day, I’m clarifying it on paper, and as soon as all ambiguity is lifted, I’m working on the dev ![]()
By the way @pierre-gilles I wanted to share a remark I made: I had a lot of trouble when I created the device deletion action. I was inspired by the RTSP Camera action.js.
The problem comes from the condition:
In RTSP Camera, the condition is written like this:
if(device.created_at)
However, by doing console.log, I observe that the variable is
device.createdAt
And just because of that, my cameras do not disappear from my DB when I click delete ![]()
A guideline for the API structure: Open or Closed:
Closed API:
The Arduino module only runs a .ino code made for the Gladys module. It is perfectly complete and has no bugs.
The problem if I retrieved an Arduino code from another source, it cannot be integrated.
Open API: a sub-service is a function, a copy-paste of any working Arduino code. You just need to get those necessary for the sub-services as arguments.
{
« service »: « MyFunctionFoundOnInternet »,
« message »: {
« ARG1 »: DataPin,
« ARG2 »: The_code_to_send
« ARG3 »: « I don’t know what parameter is useful to the function »
… 5 Arguments would be enough?
}
}
In the .ino code:
Void loop()
On serial event: If « Service » = « MyFunctionFoundOnInternet » then execute MyFunctionFoundOnInternet (ARG1, ARG2, ARG3..);
Copy/paste from the internet
MyFunctionFoundOnInternet (int DataPin, The_code_to_send, etc..)
{ bla, bla, bla }
My other sub-services
SendRadioCode(DataPin, The_code_to_send, protocol, etc) {}
SendIRcode (){}
Done like this, if the guy messes up and puts « A » in the Pin argument, it crashes.
Finally, in a tutorial, everyone can make « their » Arduino code by replacing the arguments in Gladys.
@benPi to be honest, your 2 proposals are not incompatible… In a way.
What I had in mind: a .ino made for the Gladys module, finished and bug-free. However, this code would be composed precisely of certain functions, which themselves act as sub-services as you described.
For example, in a first step, the first sub-service will be the 433 MHz transmission. Then I will add the 433 MHz for Chacon. Then the IR transmission. Each of these features will have its own function in the Arduino, which will be called upon interaction with the device.
We need to take it step by step while we are on the basics.
Moreover, nothing prevents this ino file from being evolvable. A first version can be released, then, when the need arises, we will update the service with the new features, and we will propose a new version of the Arduino code.
Tiens un exemple (c’est pas propre désolé), de plusieurs sous services dans l’arduino
On envoi les arguments en JSON nécessaires à la fonction en question. J’ai commenté au max pour que tu voies le raisonnement.
/*
* Receiver is not mandatory !!
* You can just have a emitter.
*
* Configuration
* Pin D2 => interruption 0 => radio receiver
* Pin D10 => 433Mhz emitter
*
* Wait for a JSON on serial port. When a JSON is received, it calls the right function
* Code example : (the % is for the end of the command). Put thats code into the serial to test
*
* {"function_name":"SendRadioCode","ARG1":"5502227","ARG2":1,"ARG3":218}%
* => call the SendRadioCode function with code "5502227" CANAL 1 PULSELENGTH 218
*/
/*
* IRrecord: record and play back IR signals as a minimal
* An IR detector/demodulator must be connected to the input RECV_PIN.
* An IR LED must be connected to the output PWM pin 3.
* A button must be connected to the input BUTTON_PIN; this is the
* send button.
* A visible LED can be connected to STATUS_PIN to provide status.
*
* The logic is:
* If the button is pressed, send the IR code.
* If an IR code is received, record it.
*
* Version 0.11 September, 2009
* Copyright 2009 Ken Shirriff
* http://arcfn.com
*/
/*PHOTOCELL simple testing sketch.
Connect one end of the photocell to 5V, the other end to Analog 0.
Then connect one end of a 10K resistor from Analog 0 to ground
For more information see http://learn.adafruit.com/photocells */
// SERVICES: RF_433_COM, SERVO_MVT, IR_COM, PHOTOCELL,PIR MVT detector
#include <ArduinoJson.h> // SERIAL_COM
#include <RCSwitch.h> // RF_433_COM
#include <Servo.h> // SERVO_MVT
#include <IRremote.h> // IR_COM
//DEFINITION PINS
//PHOTOCELL
int pinPhotoCell = 0; // A0 the cell and 10K pulldown are connected to A0
//PIR
int pinPIR = A1; //PIN 15 = A1
//SERVO
int pinServo = 9;//PWM PIN ONLY check TODO: http://....
//RF_433_COM
int pinRF_433_COMrcv = 0;
int pinRF_433_COMsend = 10;
// IR_COM
int RECV_PIN = 11; // CONNECT TO DATA IR RCVR
int BUTTON_PIN = 12; // BUTTON TO PRESS TO SEND IR CODE: just for tests
int STATUS_PIN = 13; // UNIVERSAL LED RETURN STATUS = ARDUINO WORKING
// OBJECTS AND VARIABLES
//PHOTOCELL
int photocellReading; // the analog reading from the analog resistor divider A0
int luminosite; // PHOTOCELL INTENSITY FROM 0 TO 1024
//SERVO
int angle; // variable to hold the angle for the servo motor 0-180°
int i; // incréments servomoteur
Servo myServo; // SERVO
//RF_433_COM
RCSwitch mySwitch = RCSwitch(); //RF_433_COM
//IR_COM
IRrecv irrecv(RECV_PIN);//IR_COM
IRsend irsend; //IR_COM
decode_results results; //IR_COM
// SERVICES
// SERVICE SEND RF_433_COM:
void SendRadioCode(long code, int canal, int pulseLength) {
// PulseLength and Canal are sets in Gladys module.
// Default to 1 & 100. Will work on most devices. Check deviceType conf to adjust to your needs.
mySwitch.setProtocol(canal, pulseLength);
mySwitch.send(code, 24);
}
// SERVICE SEND IR_COM:
void sendIRCode(int repeat,unsigned long codeValue,int codeType,int codeLen,unsigned int rawCodes[RAWBUF],int toggle ) {
/* FOR INFO
* The type of code codeType default is -1
unsigned long codeValue; // The code value if not raw
unsigned int rawCodes[RAWBUF]; // The durations if raw
int codeLen; // The length of the code
int toggle = 0; // The RC5/6 toggle state
**/
if (codeType == NEC) {
if (repeat) {
irsend.sendNEC(REPEAT, codeLen);
Serial.println("Sent NEC repeat");
}
else {
irsend.sendNEC(codeValue, codeLen);
Serial.print("Sent NEC ");
Serial.println(codeValue, HEX);
}
}
else if (codeType == SONY) {
irsend.sendSony(codeValue, codeLen);
Serial.print("Sent Sony ");
Serial.println(codeValue, HEX);
}
else if (codeType == PANASONIC) {
irsend.sendPanasonic(codeValue, codeLen);
Serial.print("Sent Panasonic");
Serial.println(codeValue, HEX);
}
else if (codeType == JVC) {
irsend.sendJVC(codeValue, codeLen, false);
Serial.print("Sent JVC");
Serial.println(codeValue, HEX);
}
else if (codeType == RC5 || codeType == RC6) {
if (!repeat) {
// Flip the toggle bit for a new button press
toggle = 1 - toggle;
}
// Put the toggle bit into the code to send
codeValue = codeValue & ~(1 << (codeLen - 1));
codeValue = codeValue | (toggle << (codeLen - 1));
if (codeType == RC5) {
Serial.print("Sent RC5 ");
Serial.println(codeValue, HEX);
irsend.sendRC5(codeValue, codeLen);
}
else {
irsend.sendRC6(codeValue, codeLen);
Serial.print("Sent RC6 ");
Serial.println(codeValue, HEX);
}
}
else if (codeType == UNKNOWN /* i.e. raw */) {
// Assume 38 KHz
irsend.sendRaw(rawCodes, codeLen, 38);
Serial.println("Sent raw");
}
}
// SERVICE SERVO:
void setServo(int angle,int pin) {
// set the servo position
myServo.attach(pin); // attaches the servo on pin 9 to the servo object
myServo.write(angle);
}
// SERVICE PIR MVT:
void pirMvt(){
if (analogRead (A1)>200){
Serial.println(analogRead (A1));
angle = map(i, 0, 1023, 0, 179);
Serial.print("angle: ");
Serial.println(angle);
// set the servo position
myServo.write(angle);
}
else
{
digitalWrite(7,HIGH);
}
}
// SERVICE PHOTOCELL:
void photocell (){
// CODE PHOTOCELL
photocellReading = analogRead(pinPhotoCell);
// We'll have a few threshholds, qualitatively determined
if (photocellReading < 10 ) {
Serial.println(" - Noir");
} else if (photocellReading < 200) {
Serial.println(" - Sombre");
} else if (photocellReading < 500) {
Serial.println(" - Lumiere");
} else if (photocellReading < 800) {
Serial.println(" - Lumineux");
} else {
Serial.println(" - Tres lumineux");
}
}
// READ serial: MAIN XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// Serial buffer
String command = "";
// End of command marker
char endMarker = '%';
/**SEND SERIAL TO ARDUINO
* This function is automatically called when data is received on serial port /CHOOSE THE GOOD SERVICE
*/
void serialEvent() {
//lit toutes les données (vide le buffer de réception)
char last_readed_char = Serial.read();
if ( last_readed_char == endMarker ) { // Si dernier caractère est % alors c'est une commande => executeFunction
executeFunction(command);
command = "";
} else {
command += last_readed_char;
}
}
/*
* Execute the right function = Command recieved via serial {"function_name":"SendRadioCode","ARG1":"5502227","ARG2":1,"ARG3":218}%
* THAT IS {"function_name":"SendRadioCode","ARG1":ARG[1],"ARG2":ARG[2],"ARG3":ARG[3],"ARG4":ARG[4]}%
*/
void executeFunction(String json_data) {
StaticJsonBuffer<200> jsonBuffer;
JsonObject& v = jsonBuffer.parseObject(json_data);//on décompose la chaine de cartère
// TODO: int ARG[]=[v["ARG1"],v["ARG2"],v["ARG3"],v["ARG4"]]; // ARRAY WITH ALL GLADYS ARGUMENTS COMMING WITH THE COMMAND
long ARG1=v["ARG1"]; //USUALLY THE CODE?
int ARG2=v["ARG2"]; //USUALLY CANAL?
int ARG3=v["ARG3"]; //USUALLY PULSELENTH? TODO: define as unsigned to work with IR_COM
unsigned int ARG4=v["ARG4"]; //USUALLY PIN NUMBER?
// COMMAND "SENDRADIOCODE"=> RF_433_COM
if ( v["function_name"] == String("SendRadioCode") )
{
SendRadioCode( ARG1, ARG2, ARG3);
// Serial.println("ARG1: " & canal, "ARG2: " & pulselength, "ARG3: " & code);
}
//COMMAND "sendIRCode" => IR_COM
if ( v["function_name"] == String("sendIRCode") )
{
sendIRCode(1,ARG1,ARG3, ARG2,ARG4,0);
}
//COMMAND "setServo" => SERVO
if ( v["function_name"] == String("setServo") )
{
setServo(ARG1,ARG2);
}
}
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
// Receiver RF_433_COM is connected on Arduino Pin #2 by default
mySwitch.enableReceive(pinRF_433_COMrcv);
// Transmitter RF_433_COM is connected to Arduino Pin #10 by default
mySwitch.enableTransmit(pinRF_433_COMsend);
// Optional set pulse length.
mySwitch.setPulseLength(385);
// Optional set protocol (default is 1, will work for most outlets)
mySwitch.setProtocol(1);
// Optional set number of transmission repetitions.
mySwitch.setRepeatTransmit(15);
//PIRPIN A1 = 15
pinMode (A1, INPUT); // Sortie PIR sur A1
pinMode (7,OUTPUT); // SORTIE D7 = LED TEST
digitalWrite(7,HIGH);
delay(1000);
// SERVICE IR_COM/
irrecv.enableIRIn(); // Start the receiver
pinMode(BUTTON_PIN, INPUT);
pinMode(STATUS_PIN, OUTPUT); // TEMOIN LUMINEUX DE FONCTIONNEMENT?
}
/*
* <IR_COM> SERVICE
*/
// Storage for the recorded code
//int codeType = -1; // The type of code
//unsigned long codeValue; // The code value if not raw
//unsigned int rawCodes[RAWBUF]; // The durations if raw
//int codeLen; // The length of the code
//int toggle = 0; // The RC5/6 toggle state
// Stores the code for later playback
// Most of this code is just logging
/*
void storeCode(decode_results *results) {
int codeType = results->decode_type;
int count = results->rawlen;
if (codeType == UNKNOWN) {
Serial.println("Received unknown code, saving as raw");
codeLen = results->rawlen - 1;
// To store raw codes:
// Drop first value (gap)
// Convert from ticks to microseconds
// Tweak marks shorter, and spaces longer to cancel out IR receiver distortion
for (int i = 1; i <= codeLen; i++) {
if (i % 2) {
// Mark
rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK - MARK_EXCESS;
Serial.print(" m");
}
else {
// Space
rawCodes[i - 1] = results->rawbuf[i]*USECPERTICK + MARK_EXCESS;
Serial.print(" s");
}
Serial.print(rawCodes[i - 1], DEC);
}
Serial.println("");
}
else {
if (codeType == NEC) {
Serial.print("Received NEC: ");
if (results->value == REPEAT) {
// Don't record a NEC repeat value as that's useless.
Serial.println("repeat; ignoring.");
return;
}
}
else if (codeType == SONY) {
Serial.print("Received SONY: ");
}
else if (codeType == PANASONIC) {
Serial.print("Received PANASONIC: ");
}
else if (codeType == JVC) {
Serial.print("Received JVC: ");
}
else if (codeType == RC5) {
Serial.print("Received RC5: ");
}
else if (codeType == RC6) {
Serial.print("Received RC6: ");
}
else {
Serial.print("Unexpected codeType ");
Serial.print(codeType, DEC);
Serial.println("");
}
Serial.println(results->value, HEX);
codeValue = results->value;
codeLen = results->bits;
}
}
**/
int lastButtonState;
// </IR_COM>
void loop() {
// Capteur PIR
pirMvt();
// PHOTOCELL
photocell ();
// <RF_433_COM_RCV>
if (mySwitch.available()) {
int value = mySwitch.getReceivedValue();
// ACTIVE THIS TO KNOW bitlength, delay and protocol to set at the learning phase
/*int lenght = mySwitch.getReceivedBitlength();
int delais = mySwitch.getReceivedDelay();
int protocol= mySwitch.getReceivedProtocol();*/
if (value == 0) {
Serial.print("Unknown encoding");
} else {
Serial.print("{\"action\":\"received\",\"value\":");
Serial.print( mySwitch.getReceivedValue() );
Serial.println("}");
// ACTIVE THIS TO KNOW bitlength, delay and protocol to set at the learning phase
/* Serial.print(mySwitch.getReceivedBitlength());
Serial.print(mySwitch.getReceivedDelay());
Serial.print (mySwitch.getReceivedProtocol());*/
}
delay(200);
mySwitch.resetAvailable();
}
// </RF_433_COM_RCV>
// <IR_COM SERVCE>
// If button pressed, send the code.
int buttonState = digitalRead(BUTTON_PIN);
if (lastButtonState == HIGH && buttonState == LOW) {
Serial.println("Released");
irrecv.enableIRIn(); // Re-enable receiver
}
if (buttonState) { // IF YOU PRESS BUTTON
Serial.println("Pressed, sending");
digitalWrite(STATUS_PIN, HIGH);
//sendIRCode(lastButtonState == buttonState, ,,,); put an example IR code to try
digitalWrite(STATUS_PIN, LOW);
delay(100); // Wait a bit between retransmissions
}
/*
else if (irrecv.decode(&results)) { // IF A DATA IS RECIEVED
digitalWrite(STATUS_PIN, HIGH);
storeCode(&results);
irrecv.resume(); // resume receiver
digitalWrite(STATUS_PIN, LOW);
}
*/
lastButtonState = buttonState;
// </IR_COM SERVCE>
}
I have a small issue I can’t figure out regarding the devices page.
I duplicated the setup page functionality to adapt it to the device page. Adding a device is based on the same code. So I can add as many Arduinos as I want to the DB, but when I try to add devices via the device page, I get a 422 error.
![]()
The JSON passed as a parameter in the POST API request is correct, as it displays in a console.log in the same way as the Arduinos. But I can’t see where my error is. Could you help me?
Thanks a lot ![]()
You need to add the detection of Chinese Arduino clones in setup.js
Damn, I’m starting to understand how this mess works
// foreach port we test if it is an arduino
ports.forEach(function(port) {
if (port.manufacturer && port.manufacturer.toLowerCase().search("arduino") != -1) {
arduinos.push(port);
} **else if (port.manufacturer && port.manufacturer.toLowerCase().search("qinheng") != -1){**
arduinos.push(port);
This is already planned; I’ve noted it on my roadmap. If you look at my code, you’ll notice a first list of manufacturers including Chinese clones. Additionally, on the configuration page, you can see the manufacturer of the device connected to the comPath in the list (example: /dev/TTYUSB0 - 1a86)
But for now, my priority is to resolve the issue I mentioned earlier, the 422 POST API error despite the correct syntax.
Once that’s fixed, I’ll improve these devices to provide Arduino services.
Yes! I still don’t have access to your code, I’m just bringing up issues with version 3. Just in case. If you’ve taken it into account, that’s great, for your other problem I can’t help you.
Top thanks a lot ![]()
You can see my code here:
The list of manufacturers is defined in the action.js of the page:
Currently, this is what I have done in my Arduino with Gladys, V3, it is not complicated to do, I have a button in Gladys to activate/deactivate it. If you need help, let me know.
How do you manage the sub-services? Is it in the Arduino service or depending on the Arduino code?
If it is directly in the service, why specify the Chacon? What about the others?
Actually, a service is an Arduino function that contains the code. If Gladys sends to the Arduino « service »: « RF433_CHACON », it calls this function.
Your personal Arduino code, you call it « perso » and in your perso function you put your Arduino code.
So any Arduino function can be called.
Well, it all depends on the Arduino code.
Well, everything except what concerns the way to retrieve and display the services as well as the possible interactions with Gladys, right?
In that case Yeah it’s great! ![]()





