[SOLVED]Particle.subscribe not picking up publish

I’m trying to send data over the cloud and have it activate a relay shield on another photon, all of my code looks fine, but something is keeping it from activating. I’ve checked the logs and photon “A” is publishing the event and data, but photon “B” isn’t picking it up, or something is keeping it from activating. Anyone have any insight for this?

Here is the code for the relay shield “photon B”:

#include "Particle.h"
#include "application.h"
const int WIEGAND_D0_PIN = D2; // Green
const int WIEGAND_D1_PIN = D3; // White
int relay = D6;

void wiegandInterrupt(); // forward declaration
bool decodeWiegand(unsigned long value); // forward declaration
void myHandler();

volatile int cardBitCount = 0;
volatile unsigned long cardValue = 0;
volatile unsigned long cardReadStart = 0;

void setup() {
Particle.subscribe("RGS2", myHandler, MY_DEVICES);
pinMode(relay, INPUT_PULLDOWN);
	Serial.begin(9600);

	// Wiegand pulse are narrow, typically 100 microseconds, so interrupts are desirable to accurately
	// detect them
	attachInterrupt(WIEGAND_D0_PIN, wiegandInterrupt, FALLING);
	attachInterrupt(WIEGAND_D1_PIN, wiegandInterrupt, FALLING);
}

void loop() {
	if (cardReadStart != 0) {
		if (cardBitCount == 26) {
			// Got a valid 26-bit card
			if (decodeWiegand(cardValue)) {
				// Is valid
				Particle.publish("RGS1", String(cardValue), PRIVATE);
			}
			cardReadStart = 0;
			cardBitCount = 0;
		}
		else
		if (millis() - cardReadStart > 500) {
			Serial.println("failed to read enough bits");
			cardReadStart = 0;
			cardBitCount = 0;
		}
	}
}

void wiegandInterrupt() {
	if (cardBitCount == 0) {
		cardReadStart = millis();
		cardValue = 0;
	}
	else {
		cardValue <<= 1;
	}

	if (pinReadFast(WIEGAND_D1_PIN) == LOW) {
		cardValue |= 1;
	}
	cardBitCount++;
}

void myHandler(const char *event, const char *data)
{

  if (strcmp(data,"open")==0) {
    
    digitalWrite(relay,HIGH);
    delay(5000);
    digitalWrite(relay,LOW);
  }
}
// Note: in the following table the bit numbers are 0-based, 0 - 25 for a 26-bit Wiegand code!
// Bit 25: Even parity, first half of bits
// Bits 24 - 17: Facility code, MSB first 0 - 255
// Bits 16 - 1: Card code, MSB first, 0 - 65536
// Bit 0: Odd parity, second half of bits
bool decodeWiegand(unsigned long value) {
	bool valid = false;

	int facility = (value >> 17) & 0xff;
	int card = (value >> 1) & 0xffff;

	unsigned long tempValue = value;
	int parity = 0;
	for(int ii = 0; ii < 13; ii++) {
		if (tempValue & 1) {
			parity++;
		}
		tempValue >>= 1;
	}
    if ((parity & 0x1) == 1) {
    	// First parity passed
    	parity = 0;
		for(int ii = 0; ii < 13; ii++) {
			if (tempValue & 1) {
				parity++;
			}
			tempValue >>= 1;
		}
		if ((parity & 0x1) == 0) {
			// Second parity passed; looks valid
			Serial.printlnf("value=0x%x facility=%d card=%d", value, facility, card);
			valid = true;
		}
		else {
	    	Serial.printlnf("even parity error value=0x%x", value);
		}
    }
    else {
    	Serial.printlnf("odd parity error value=0x%x", value);
    }
    return valid;
}

and the code for “Photon A”:

// This #include statement was automatically added by the Particle IDE.
#include "Particle.h"
#include "SparkIntervalTimer.h"


void subscriptionHandler(const char *event, const char *data); // forward declaration
void senderInterrupt(); // forward declaration

const int WIEGAND_D0_PIN = D2; // Green
const int WIEGAND_D1_PIN = D3; // White
int relay = D7;

const int TIMER_PERIOD_US = 100;
const int LOW_PERIOD = 1;
const int HIGH_PERIOD = 10;

IntervalTimer timer;
int sendBitsLeft = 0;
int sendPeriod = 0;
unsigned long sendValue;

void setup()
{
    pinMode(relay, INPUT_PULLDOWN);
	Serial.begin(9600);
    
	pinMode(WIEGAND_D0_PIN, OUTPUT);
	digitalWrite(WIEGAND_D0_PIN, HIGH);

	pinMode(WIEGAND_D1_PIN, OUTPUT);
	digitalWrite(WIEGAND_D1_PIN, HIGH);

	timer.begin(senderInterrupt, TIMER_PERIOD_US, uSec);
    
	Particle.subscribe("RGS1", subscriptionHandler, MY_DEVICES);
	
}

void loop() {

if (digitalRead(relay)==HIGH) {
        Particle.publish("RGS2","open", MY_DEVICES);
        delay(10);
        digitalWrite(relay, LOW);
        delay(5000);
    }
}
void subscriptionHandler(const char *event, const char *data) {
	unsigned long value = strtoul(data, NULL, 0);
	Serial.printlnf("received value=0x%x", value);
	sendPeriod = 0;
	sendValue = value;
	sendBitsLeft = 26;
}

void senderInterrupt() {
	if (sendBitsLeft > 0) {
		if (sendPeriod == HIGH_PERIOD) {
			sendPeriod = 0;
		}

		if (sendPeriod == 0) {
			// Write out the data bit
			if ((sendValue >> (sendBitsLeft - 1)) & 1) {
				// 1 bit
				digitalWrite(WIEGAND_D1_PIN, LOW);
			}
			else {
				// 0 bit
				digitalWrite(WIEGAND_D0_PIN, LOW);
			}
		}
		else
		if (sendPeriod == LOW_PERIOD) {
			// Restore high
			digitalWrite(WIEGAND_D0_PIN, HIGH);
			digitalWrite(WIEGAND_D1_PIN, HIGH);
			sendBitsLeft--;
		}

		sendPeriod++;
	}
}

Also, the way “Photon B” is wired, D3 is pulled high all the time, I don’t know if this makes a difference. I can change the wires and the code to get away from D3 if I need to.

pinMode(relay, INPUT_PULLDOWN);

I think that should be OUTPUT to activate the relay on Photon B using digitalWrite.

Take another look at your publishes. From the docs:
"Publish a private event with the given name, data, and TTL. In order to publish a private event, you must pass all four parameters."
https://docs.particle.io/reference/firmware/photon/#particle-publish-

1 Like

I knew it was going to be something I’ve overlooked. Thanks again @rickkas7. @Moors7, I’ll change this, but I saw in another thread where this wasn’t a requirement and the docs were just outdated. Either way, its probably not bad practice to do this.

Regardless, ‘MY_DEVICES’ in a publish is incorrect, and presumably the reason why it’s not picking up on the receiving end.

1 Like

Sorry, but the docs seem outdated there.
There is a three-parameter overload for PRIVATE publishes

    inline bool publish(const char *eventName, const char *eventData, PublishFlag eventType=PUBLIC)
    {
        return CLOUD_FN(spark_send_event(eventName, eventData, 60, PublishFlag::flag_t(eventType), NULL), false);
    }
2 Likes

@moors7 I removed the “MY_DEVICES” parameter and between that and changing the pin to output, we’re good to go. Thanks as usual guys, all is well.

@mjones Can you please repost your final code for both A and B, I’m new to coding and trying to work out where I’m going wrong with this? I don’t get any compile errors but not receiving the wiegand data on side B. Your help would be greatly appreciated. thanks