RF 433 Mhz on virtual pin doesn't want to send (with scheduling)

@Costas - Thanks for that.
I’m not 100% sold on the idea of a cheap tablet for controlling the outside lights. There’s a good chance that drinks will get spilled on it or that kids will mess around with it, hence the idea of a simple garage door opener style remote. It might still get drinks spilled on it, but cheaper to replace and it doesn’t need to be charged up.
I could locate a 433Mhz receiver and Wemos near the seating area without too much hassle, so I could overcome the range issue.
What sort of range do you get indoors with brick walls?

Pete.

I was thinking cheap phone not tablet, the sort of thing modern kids wouldn’t go anywhere near.

A programmable RF key fob could be used in place of the Android phone and local server but then you wouldn’t get the remote updates of the Toldos’ that you were looking for.

We have a modest sized 3 bedroom apartment all on one level so we don’t have any problems with range. We run the transmitters off the 5V feed on the WeMos but they will accept 12V if you need the extra range.

1 Like

Thanks for that @Costas, plenty of food for thought to keep the grey matter ticking over ‘till I’m back in Spain again.

One quick question that might save me a bit of time - what 433Mhz library do you use with the Wemos?

Pete.

We use this library which I believe was updated to cover ESP’s some time ago https://github.com/sui77/rc-switch

We also have our own code for some devices that are not covered by regular protocols.

1 Like

I guess it makes more sense to call it a hub or gateway. Easier to relate to what I’m aiming for. I hope…
I haven’t planned to use any extra sensors at the moment, just my remotes. Friends and family must be able to turn the lights on/off even if I’m not at home. And yes, I’m aware of the fact that a remote do just that! :smiley: But to overcome some erratic problems with range and interference, my “hub” will also re-transmit any (valid) signals. One step at the time!

Wow! And I thought I had problems :laughing:
Perhaps this interests you 433toMQTTto433? I haven’t had much time to look into it myself yet, but someday…

That looks like exactly what I’m trying to achieve - thanks @distans
I can’t wait to get back to Spain and pick-up my 433Mhz hardware then start experimenting.
I’ve already lashed together something similar to their IR controller on a breadboard to control the aircon and ceiling fans, but it needs to be turned into a permanent solution and boxed-up, and the code needs tidying up a bit, but I think I’ll compare their circuit with mine before I settle on the final solution.

Pete.

The hardware problem is that the cheap XY-MK-5V receivers starts to self oscillate in the absence of a real signal, which creates the “no signal noise” on the data out pin (but I guess you know all this).

The software problem is that I can’t use interrupts on the data pin to catch signals. It gets triggered all the time due to the noise, halting everything and makes Blynk go bananas (if I’m lucky) before it disconnects. There is probably some tweaks that could make this setup work better, but that’s beyond my grasp.

Well… yes and no. I wanted to test Blynk over a little longer period of time to figure out my actual needs, difficulty to use, QoS etc. It felt better to learn how to use what I had before buying something I didn’t need :smiley:

I’m gonna keep using 433Mhz controlled plugs, but with a LoRa/ISM RF instead. Probably hooked up to a Wemos D1 Mini. But having a hard time deciding on which transceiver I want :face_with_raised_eyebrow:

It’s time to put this thread to rest. From my initial problems, the experiment evolved to form a gateway, including an extra MCU to tame the dreaded XY-MK-5V super regenerative receiver. The plan was to use an ATTiny85 as the second MCU, but I’vent got around to buy one yet, so 2 x Arduino UNO R3 have been used instead.

After extensive testing I’ve got it working, but not without issues :face_with_raised_eyebrow: There are some intermittent network problems I can’t figure out. But as long as I don’t “overload” the master MCU with ISR’s, it’s rarely a problem. I’ll post a new thread for this in Issues and Errors (I think it’s protocol related). A better write-up will be posted in Projects Made… but in short: 433 Mhz power plugs controlled with Blynk and/or physical remote controller and maintaining correct status in app.

SLAVE - decodes signals from my remote controller and sends it to MASTER via serial (and make some noise).
MASTER - handles Blynk and SLAVE requests, scheduling, a temp sensor and of course - transmitting to the power plugs.

The code for “peer review” :wink:

/**
	used togheter with RF433_Master.ino
**/

#include "NexaSelfLearningReceiver.h"

#define GND			2	// Receiver plugged directly to the board
#define VCC			5	// "
#define RX_PIN		3	// Could be 4
#define RX_LED		13	// Built in LED

uint32_t hardCodedRC = 1912830; // My remote controlers hardcoded ID. 

int ISR_Pin = 11; 		// To: MASTER pin 2. Set HIGH to invoke ISR
int signalPin = 12; 	// From: MASTER pin 9. If HIGH, don't decode (= Master is sending)		
int piezoPin = 8;      	// Make some Noice (Yes, phun intended! Noice is a Swedish late 70-80 punk rock group ;) )

//============

NexaSelfLearningReceiver receiver = NexaSelfLearningReceiver(RX_PIN, RX_LED);
uint32_t transmitter = 0;
bool on = false;
bool group = false;
uint8_t channel = 0;
short dim = 0;
uint64_t receivedSignal = 0;

//============ Piezo

unsigned int highHz = 2000; 	// Hz
unsigned int lowHz = 1700; 		// Hz
unsigned long duration = 30; 	// milliseconds 

//============

void setup(){
  	pinMode(ISR_Pin, OUTPUT);  	
  	digitalWrite(ISR_Pin, LOW);	// It kinda bounces during startup, triggering the ISR on MASTER
  	pinMode(signalPin, INPUT);  // 
  	pinMode(GND, OUTPUT);		// Give Rx GND and VCC
  	pinMode(VCC, OUTPUT);		// " 
  	digitalWrite(GND, LOW);		// "
  	digitalWrite(VCC, HIGH);	// "
    Serial.begin(115200);
    Serial.println("In the beginning ..");
    tone(piezoPin, highHz, duration);
};

//============

void loop() {
    receivedSignal = receiver.receiveSignal(&transmitter, &on, &group, &channel, &dim, 1000);

    // Stop receiving when transmitter is sending to avoid disco
    if (digitalRead(signalPin) == LOW) {
	    // Just want my RC
	    if(receivedSignal != 0 && transmitter == hardCodedRC) {

	        Serial.print("<");	// startMarker
	        Serial.print(transmitter);
	        Serial.print(",");
	        Serial.print(on);
	        Serial.print(",");
	        Serial.print(channel);
	        Serial.print(",");
	        Serial.print(group);
	        Serial.print(",");
	        Serial.print(dim);
	        Serial.print(">");	// endMarker
	        Serial.println(""); 

			delay(10);        				// All chars in MASTERs buffer?
			digitalWrite(ISR_Pin, HIGH);  	// Notify MASTER about incomming data
			delayMicroseconds(50);        	// Seems like it need some time to react?
			digitalWrite(ISR_Pin, LOW);	 

			// Make a short beep so I know it received and decoded the signal. High pitch - ON, low = OFF
			if (on) {
			  tone(piezoPin, highHz, duration);
			}
			else {
			  tone(piezoPin, lowHz, duration);
			}
	    }
    }
}

It looks like the network problem was caused by a lengthy ISR routine so I’ve removed my previous post. Today’s lesson -The serial buffer doesn’t need an interrupt and holds 64 bytes which is more than enough for the data :slight_smile:

/**
Used togheter with RF433_Slave.ino

2017-10-25 21:56:45 - Removed parse data routine to a timer instead of ISR to keep it shorter. The time spent in ISR
sometimes collided with ethernet ACK's from the Blynk server and then freezing the board. Lessons learned!

2017-10-25 22:42:32 - Removed ISR altogether! The serial buffer holds 64 bytes and doesn't need an interrupt :) Using timer instead.

**/

#define BLYNK_PRINT Serial
#include <NexaSelfLearningTransmitter.h>
#include <SPI.h>
#include <Ethernet.h>
#include <BlynkSimpleEthernet.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

const byte W5100_CS = 10;
const byte SDCARD_CS = 4;

//============ MASTER <- -> SLAVE

const byte signalPin = 9;     // To: SLAVE pin 12. Set to HIGH when transmitting

//============ Temp sensor

const byte ONE_WIRE_BUS = 3;

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);

//============ Transmitter

uint8_t TX_PIN = 8;
uint8_t TX_LED = 7; // Not connected, but need to be defined (and W5100 uses 13).

NexaSelfLearningTransmitter transmitter = NexaSelfLearningTransmitter(TX_PIN, TX_LED);

bool on = false;
bool group = false;
short dim = 0;
uint8_t channel = 0;
uint64_t receivedSignal = 0;
uint32_t TRANSMITTER_ID = 1912830;

//============ Parsed data
																
const byte numChars = 26; // Needs to hold something like this <1912830,1,14,0,-1> 
char receivedChars[numChars];
char tempChars[numChars];
long int pTransmitter;
int pOn;
int pGroup;
int pChannel;
int pDim;
bool newData = false;

//============ Blynkkk stuff

WidgetTerminal terminal(V4);
BlynkTimer timer;
WidgetRTC rtc;

char currentTime[9];
bool clockSync = false;
char auth[] = "";

byte arduino_mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xCC };
IPAddress arduino_ip (192, 168,   0,  20);
IPAddress dns_ip     (192, 168,   0,   1);
IPAddress gateway_ip (192, 168,   0,   1);
IPAddress subnet_mask(255, 255, 255,   0);


//============ Setup

void setup() {

	pinMode(signalPin, OUTPUT);
	digitalWrite(signalPin, LOW);   // HIGH when sending
	pinMode(SDCARD_CS, OUTPUT);
	digitalWrite(SDCARD_CS, HIGH);  // Deselect the SD card
	Serial.begin(115200);
	Serial.println();
	DS18B20.begin();
	Blynk.begin(auth, "cloud.blynk.cc", 8442, arduino_ip, dns_ip, gateway_ip, subnet_mask, arduino_mac);

	while (Blynk.connect() == false) {
		// Wait until connected
	}

	for (int i = 0; i <= 24; i++) {
		terminal.println("");     // "clear screen" in app.
	}

	terminal.flush();
	terminal.println(F("Blynk v" BLYNK_VERSION ": Device started"));
	terminal.println(F("-------------"));
	terminal.flush();
	timer.setInterval(60000L, activetoday);     // check every 60s if ON / OFF trigger time has been reached
	timer.setInterval(30000L, reconnectBlynk);  // check every 30s if still connected to server
	timer.setInterval(5000L, clockDisplay);     // check every 5 second if time has been obtained from the server
	timer.setInterval(60000L, getSensorData);   // get temp sensor every 60s
	timer.setInterval(1000L, readSerialBuffer);	// check for new data in buffer every second
}

void timeStamp() {
	clockSync = false;
	clockDisplay();
}
BLYNK_CONNECTED() {
	rtc.begin();
}

void activetoday(){               // check if schedule should run today
	if(year() != 1970){
		Blynk.syncVirtual(V10);     // sync scheduler #1
	}
}

void clockDisplay(){            // only needs to be done once after time sync
	if((year() != 1970) && (clockSync == false)){
		sprintf(currentTime, "%02d:%02d:%02d", hour(), minute(), second());
		Serial.println(currentTime);
		terminal.println(currentTime);
		terminal.flush();
		clockSync = true;
	}
}

BLYNK_WRITE(V10) {   // Scheduler #1 Time Input widget

	TimeInputParam t(param);
	unsigned int nowseconds = ((hour() * 3600) + (minute() * 60) + second());
	unsigned int startseconds = (t.getStartHour() * 3600) + (t.getStartMinute() * 60);
	unsigned int stopseconds = (t.getStopHour() * 3600) + (t.getStopMinute() * 60);
	int dayadjustment = -1;
	if(weekday() == 1){
		dayadjustment = 6; // needed for Sunday Time library is day 1 and Blynk is day 7
	}
	if(t.isWeekdaySelected((weekday() + dayadjustment))){ //Time library starts week on Sunday, Blynk on Monday
		//Schedule is ACTIVE today
		if(nowseconds >= startseconds - 31 && nowseconds <= startseconds + 31 ){    // 62s on 60s timer ensures 1 trigger command is sent
			digitalWrite(signalPin, HIGH);        // Tells SLAVE to ignore transmission
			transmitter.deviceOn(TRANSMITTER_ID, 15); // Doesnt always work for some reason
			Blynk.virtualWrite(V0, 1);              // This however always work as long as it's connected to internet
			Blynk.syncVirtual(V0);
			Serial.println("Schedule 1 started");
			terminal.println("Schedule 1 started");
			terminal.flush();
			timeStamp();
			digitalWrite(signalPin, LOW); // OK for SLAVE to receive again
		}

		if(nowseconds >= stopseconds - 31 && nowseconds <= stopseconds + 31 ){   // 62s on 60s timer ensures 1 trigger command is sent
			digitalWrite(signalPin, HIGH);
			transmitter.deviceOff(TRANSMITTER_ID, 15);
			Blynk.virtualWrite(V0, 0);
			Blynk.syncVirtual(V0);
			Serial.println("Schedule 1 finished");
			terminal.println("Schedule 1 finished");
			terminal.flush();
			timeStamp();
			digitalWrite(signalPin, LOW);
		}
	}
}

BLYNK_WRITE(V0) {                 // Unit (plug) 1

	digitalWrite(signalPin, HIGH);  // Tells SLAVE to ignore transmission

	if ( param.asInt() == 1 ) {
		transmitter.deviceOn(TRANSMITTER_ID, 15);
		Serial.println("RC 1 ON");
		terminal.println("RC 1 ON");
		terminal.flush();
	}
	else {
		transmitter.deviceOff(TRANSMITTER_ID, 15);
		Serial.println("RC 1 OFF");
		terminal.println("RC 1 OFF");
		terminal.flush();
	}

	digitalWrite(signalPin, LOW);   // OK for SLAVE to receive again
}

BLYNK_WRITE(V1) {                 // Unit 2

	digitalWrite(signalPin, HIGH);

	if ( param.asInt() == 1 ) {
		transmitter.deviceOn(TRANSMITTER_ID, 14);
		Serial.println("RC 2 ON");
		terminal.println("RC 2 ON");
		terminal.flush();
	}
	else {
		transmitter.deviceOff(TRANSMITTER_ID, 14);
		Serial.println("RC 2 OFF");
		terminal.println("RC 2 OFF");
		terminal.flush();
	}

	digitalWrite(signalPin, LOW);
}

BLYNK_WRITE(V2) {                 // Unit 3

	digitalWrite(signalPin, HIGH);

	if ( param.asInt() == 1 ) {
		transmitter.deviceOn(TRANSMITTER_ID, 13);
		Serial.println("RC 3 ON");
		terminal.println("RC 3 ON");
		terminal.flush();
	}
	else {
		transmitter.deviceOff(TRANSMITTER_ID, 13);
		Serial.println("RC 3 OFF");
		terminal.println("RC 3 OFF");
		terminal.flush();
	}

	digitalWrite(signalPin, LOW);
}

BLYNK_WRITE(V3) {                 // Group, all units

	digitalWrite(signalPin, HIGH);

	if ( param.asInt() == 1 ) {
		transmitter.groupOn(TRANSMITTER_ID);
		Blynk.virtualWrite(V0, 1);
		Blynk.virtualWrite(V1, 1);
		Blynk.virtualWrite(V2, 1);
		Serial.println("ALL IS ON");
		terminal.println("ALL IS ON");
		terminal.flush();
	}
	else {
		transmitter.groupOff(TRANSMITTER_ID);
		Blynk.virtualWrite(V0, 0);
		Blynk.virtualWrite(V1, 0);
		Blynk.virtualWrite(V2, 0);
		Serial.println("ALL IS OFF");
		terminal.println("ALL IS OFF");
		terminal.flush();
	}

	digitalWrite(signalPin, LOW);

}

void reconnectBlynk() {

	if (!Blynk.connected()) {
		Serial.println("Lost connection");
		if(Blynk.connect()) {
			Serial.println("Reconnected");
		}
		else {
			Serial.println("Not reconnected");
		}
	}
}

//============ Temperature sensor

void getSensorData() {
	DS18B20.requestTemperatures();
	float temp = DS18B20.getTempCByIndex(0);
	float roundedValue = ceilf(temp * 100) / 100; // well...
	Serial.println(roundedValue);
	Blynk.virtualWrite(5, roundedValue);
}

//============ Check serial buffer and parse data

void readSerialBuffer() {

	if (newData == false) {
		recvWithStartEndMarkers();
	}

	if (newData == true) {
		strcpy(tempChars, receivedChars);		
		parseData();
		//showParsedData(); // Debug only 
		newData = false;
	}

	
}

//============ Read the serial buffer

void recvWithStartEndMarkers() {

	static bool recvInProgress = false;
	static byte ndx = 0;
	char startMarker = '<';
	char endMarker = '>';
	char rc;

	while (Serial.available() > 0) {

		rc = Serial.read();

		if (recvInProgress == true) {
			if (rc != endMarker) {
				receivedChars[ndx] = rc;
				ndx++;
				if (ndx >= numChars) {
					ndx = numChars - 1;
				}
			}
			else {
				receivedChars[ndx] = '\0'; // terminate the string
				recvInProgress = false;
				ndx = 0;
				newData = true;
			}
		}

		else if (rc == startMarker) {
			recvInProgress = true;
		}
	}
}

//============

void parseData() {      // split the data into its parts. Looks something like this <1912830,1,15,0,-1>

	char * strtokIndx;  // this is used by strtok() as an index

	strtokIndx = strtok(tempChars,","); // The string

	pTransmitter = atol(strtokIndx);    // Transmitter ID
	strtokIndx = strtok(NULL, ",");

	pOn = atoi(strtokIndx);             // ON or OFF (1 or 0)
	strtokIndx = strtok(NULL, ",");

	pChannel = atoi(strtokIndx);        // Devcie number (13, 14, 15)
	strtokIndx = strtok(NULL, ",");

	pGroup = atoi(strtokIndx);          // Group ON or OFF (1 or 0)
	strtokIndx = strtok(NULL, ",");

	pDim = atoi(strtokIndx);            // Dim values

	if (pChannel == 15 && pGroup == 0){ // Unit 1, NOTICE: Group also has 15
		Blynk.virtualWrite(V0, pOn);
		Blynk.syncVirtual(V0);
	}
	else if (pChannel == 14) {          // Unit 2
		Blynk.virtualWrite(V1, pOn);
		Blynk.syncVirtual(V1);
	}
	else if (pChannel == 13) {          // Unit 3
		Blynk.virtualWrite(V2, pOn);
		Blynk.syncVirtual(V2);
	}
	else if (pChannel == 15 && pGroup == 1) {   // Group
		Blynk.virtualWrite(V3, pOn);
		Blynk.syncVirtual(V3);
	}
}

//============ Main LOOP

void loop() {
	
	if(Blynk.connected()) {
		Blynk.run();
	}
	timer.run();
}

Again, thanks to @Costas, @PeteKnight and @Gunner and others for taking interest in my project! :+1:

@distans which RF transmitter / receiver set are you using?

For this project I’ve been using nothing but the cheapest hardware available! :rofl:

Receiver: XY-MK-5V
Transmitter: FS1000A

I’ll post in Projects made… later on with all details. Just need to be sure that the network problems actually got solved with the new code. I haven’t been able to replicate it yet so I’m hopeful. Give me a day or two :slight_smile:

1 Like

They are my favourites, top “class” hardware.

2 Likes

@Costas, can you explain why the scheduler runs in the middle of the night? Haven’t giving it much thought while testing, but it seems like it happens every day. Latest week or so it has “finished”, but before it was starting the schedule. And since it controls a lamp in my bedroom I got some unfortunate early mornings :laughing:

Any ideas? Current code is RF433_Master.ino a few posts up.

TIA

@distans can you also post a screenshot in development mode i.e. so I can see the pin settings of the widgets.

I want to set up your system here for testing but it might be a few days as my desk is covered in projects at the moment.

You might also want to add timestamps to the Serial.println() and virtualWrite() to Terminal calls, to see when the RF signal is being sent (through the night).

Ehh…?! :thinking: How do I enable dev mode @Costas? Can’t find it anywhere I’m afraid! :confounded: (using Android app 2.16.2)

I added timestamps in the scheduler a couple of weeks ago when it started the scheduler and lit up my bedroom. If I remember it correctly it did so at around 02:30. Now it’s ending it instead (at a later time). I’ve added an extra timestamp to the virtualWrite() now.

That’s why I also have a floor! :crazy_face: Take your time!

Stop the project and take a screenshot.

I was looking for some hidden menu or setting that I’d missed :flushed: Now I’m looking for the faceplant emoji :grin:
I have done some minor changes to the code, but that’s mostly on how to read the sensor without delay so it should not affect the schedule. Guess I will know for sure tonight… The new code and details will be uploaded in a Projects made tomorrow I think.

Eventor is also removed from the app.

Don’t forget common ground when you hook up the devices.

1 Like

I think that @costas wanted you to It the square (stop) symbol in the top right hand corner of the screen (so that it changes to a VCR play symbol) then take a screenshot.
That way, he’ll be able to see which pin the widgets are attached to.

Pete.

1 Like

Feeling kinda stupid now! :grimacing: I uploaded a screenshot showing the pins, but then I remembered I’d removed Eventor so I made an new one. Of course I forgot to put it in dev mode! The dubble faceplant emoji is… where? :smiley: Thanks for bringing it to my attention @PeteKnight

@Costas, here is some data that might confuse you as well:

Timer set to 14:15 - 23:30, extra finish run at approx 05:18 = stop time + 5 h 48 min.
Timer set to 14:15 - 20:30, extra finish run at approx 02:18 = stop time + 5 h 48 min.

Thinking it might has something to do with the duration of the run time (I’m out of ideas, testing everything), this morning I changed the timer to 07:45 - 08:15. No extra run yet! I have looked at the code so many times I’m probably blind to flaws now.

Anyhow, a better screenshot for your amusement :wink:

Latest code and a write-up about the project: