Lovelace Fan Control Entity Row

finity,
I’m still in the development stage.
The wemos code I have, does in fact work. I set it up in a function loop for each fan speed.
When the payload hits the wemos, it runs the function of sending 1’s and 0’s to the RF transmitter. (in honesty, this is for my gf’s house). I can’t actually test everything live, but from serial monitor, I see the payload is hitting the wemos, it publishes back the status it received.

When I call the light on/off function, HA responds as expected.

The payload on: 2, is copied from a thread, I guess a few months/years back.
It does look like I need to fix that.
Do you think that is all that needs to be changed in my fan.yaml file?

Lastly, I intend on adding also to the Wemos D1 Mini, an RF receiver. Once the remote sends a fan speed/light off on signal, the RF receiver will also receive and publish the fan state. Without getting too heavy in it, in order to multi-task arduino or wemos, you have to run some more complex code than I’m comfortable with (right now).

How it runs now and how I plan it to run:
MQTT publishes topic >> Wemos Receives topic >> runs the signal out the RF transmitter and also, after runing the RF signal, publishes the state so HA/MQTT knows what state the fan is in.

If the end-user uses the fan’s RF remote:
Signal sent to fan >> also intercepted by Wemos >> Wemos interprets signal and publishes to HA/MQTT.

I could have the Wemos send payload and simultaneously publish to its own receiver, but that requires multi-tasking/computing that I’m not yet comfortable with. Maybe someone will intercept my code and help out, but for now, that’s how it will run.

I hope this makes sense.
When I hit fan high button, I do receive the payload and in turn, the same payload is published to HA/MQTT. I can do this for medium speed and low.
Off does nothing.

Turning off/on the light also is successful.

I have not gone in to the fan’s microcontroller to flash with TASMOTA or anything. I’m essentially communicating with the fan through radio signals.
The wemos however, receives the payload, and pushes the signal to the fan. In this way, the fan is stock so that once she/we move, anyone else can still control the fan.

RF Transmitter:

For now, I’m perplexed at the javascript and custom card.
Let me know your thoughts?

I would say to not worry about the card until you get everything working in HA using the built-in control. Once that works the card should just work. (I think…)

The fan yaml code you are using is the code for a tasmota flashed fan controller (notice the “value_json.FanSpeed” lines? that’s the sub-topic tasmota uses for the speed.) so I’m pretty sure it won’t work for your use. You’ll have to come up with the correct topics and payloads to pick up the state and speed from your MQTT messages.

I guess as a start I would comment out both the “state_value_template” and “speed_value_template” and change the payload_on to “on”.

TBH, I haven’t dug thru your arduino code to see what all of the different topics/payloads are so “on”, “off”, “1”, “2”, “3” may not be the correct payloads. But I assume at least some of them are correct since you are saying the Wemos is responding to some of them correctly.

One Other thing I just saw is that you are using all upper case letters for “OFF”. are you sure that is correct? MQTT topics & payloads are case sensisitive.

I’ll go back through my coding and convert everything to lowercase.
If you go into the developer tools >> services tab in HA and go to mqtt.publish service, it is in fact possible to push payloads using uppercase, nonetheless, I’ll change everything to lower case.

I know in the past, uppercase characters weren’t accepted so what you’re saying, I hear you, I’ll change it up and report back.

Thanks Finity!

I’m not saying that everything has to be in lower case. I’m saying to be sure that whatever case you’re using you need to make sure it all matches the topics and payloads exactly when you are publishing and subscribing.

so “OFF” is perfectly fine. So is “Off” or “oFF”. Just make you use the same case in your fan yaml as the expected case coded into your MQTT messages in your arduino code. If you use “OFF” in the yaml config and “off” in your arduino sketch it won’t work.

Actually, i did look thru your code…

The low, med, hi speeds look OK but in your skecth you are using “4” for off but in your fan yaml you have “OFF” for the off payload. So those have to match.

Also there is no state for “on” for the fan in your sketch that I can see. But you are using “2” for the “on” payload (as I’ve already mentioned) which is the speed command for the medium speed.

Also I’m confused about your status topic. I only see where the status is switched in one spot at the end of any light action. But I don’t see the same status topic get updated when the fan is commanded to do something. Where does the status topic get updated for the fan state.

If it were me I would split the fan command/state topics and the light command/state topics out from each other so you can control those completely separately and minimize confusion over “is the status of ‘ON/OFF’ for the light or fort the fan?” type of stuff.

But that was all just from a cursory skim of the code. So I could be completely wrong.

I think you should eliminate the code in your sketch for the #2 fan while you are developing to minimize the confusion that the massive wall of text creates until you get all of your MQTT stuff sorted for fan #1.

Okay, I’ve done as you’ve suggested.
I’ve changed up the wemos code to eliminate one of the fans to minimize confusion. I reformatted some of it as well to try and make it more legible (I’m still a novice).


/*   
 * RF_Transmitter
 * a Home-Automation-friendly ESP8266-based MQTT Hunter Ceiling Fan RF Controller
 * 2020 essaysee
*/

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include "config.h"


boolean recordedSignal_fanlow2[] =     {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0};
boolean recordedSignal_fanmed2[] =     {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0};
boolean recordedSignal_fanhigh2[] =    {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0};
boolean recordedSignal_fanoff2[] =   {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0};
boolean recordedSignal_lightoffon2[] = {1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0};

int a;

// Mapping NodeMCU Ports to Arduino GPIO Pins
// THIS IS ALL YOU NEED TO CHANGE IN THIS FILE
#define D0 16
#define D2 15
#define D3 0
#define D4 2
#define D5 14
#define D6 12 
#define D7 13
#define D8 15
#define WIFI_SSID "wifi name"
#define WIFI_PASSWORD "wifi password"
#define MQTT_BROKER "HA installation / MQTT"
#define MQTT_CLIENTID "RF_Transmitter"
#define MQTT_USERNAME "rf"
#define MQTT_PASSWORD "rf"
#define BEDROOM2_ALIAS "Guest Bedroom 2"
#define MQTT_ROOM2_FAN_ACTION_TOPIC "bedroom/fan/2/FanSpeed"
#define MQTT_ROOM2_FAN_STATUS_TOPIC "bedroom/fan/2/status"
#define MQTT_ROOM2_LIGHT_ACTION_TOPIC "bedroom/light/2/action"
#define MQTT_ROOM2_LIGHT_STATUS_TOPIC "bedroom/light/2/status"
#define TRANSMITTER_PIN D2
#define RECEIVER_PIN D8

//THAT WAS ALL YOU NEEDED TO CHANGE IN THE FILE



const char* ssid = WIFI_SSID;
const char* password = WIFI_PASSWORD;

//const boolean static_ip = STATIC_IP;
//IPAddress ip(IP);
//IPAddress gateway(GATEWAY);
//IPAddress subnet(SUBNET);

const char* mqtt_broker = MQTT_BROKER;
const char* mqtt_clientId = MQTT_CLIENTID;
const char* mqtt_username = MQTT_USERNAME;
const char* mqtt_password = MQTT_PASSWORD;



const char* bedroom2_alias = BEDROOM2_ALIAS;
const char* mqtt_room2_fan_action_topic = MQTT_ROOM2_FAN_ACTION_TOPIC;
const char* mqtt_room2_fan_status_topic = MQTT_ROOM2_FAN_STATUS_TOPIC;

const char* mqtt_room2_light_action_topic = MQTT_ROOM2_LIGHT_ACTION_TOPIC;
const char* mqtt_room2_light_status_topic = MQTT_ROOM2_LIGHT_STATUS_TOPIC;
const int transmitter_pin = TRANSMITTER_PIN;
const int receiver_pin = RECEIVER_PIN;

String availabilityBase = MQTT_CLIENTID;
String availabilitySuffix = "/availability";
String availabilityTopicStr = availabilityBase + availabilitySuffix;
const char* availabilityTopic = availabilityTopicStr.c_str();
const char* birthMessage = "online";
const char* lwtMessage = "offline";

WiFiClient espClient;
PubSubClient client(espClient);

// Wifi setup function

void setup_wifi() {

  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.print(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

//  if (static_ip) {
//    WiFi.config(ip, gateway, subnet);
//  }

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.print(" WiFi connected - IP address: ");
  Serial.println(WiFi.localIP());
}

// Callback when MQTT message is received; calls triggerBedroomAction(), passing topic and payload as parameters

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  
  Serial.println();

  String topicToProcess = topic;
  payload[length] = '\0';
  String payloadToProcess = (char*)payload;
  triggerBedroomAction(topicToProcess, payloadToProcess);
}



// Function that publishes birthMessage

void publish_birth_message() {
  // Publish the birthMessage
  Serial.print("Publishing birth message \"");
  Serial.print(birthMessage);
  Serial.print("\" to ");
  Serial.print(availabilityTopic);
  Serial.println("...");
  client.publish(availabilityTopic, birthMessage, true);
}





// Function called by callback() when a message is received 
// Passes the message topic as the "requestedRoom" parameter and the message payload as the "requestedAction" parameter
// THIS JUST PRINTS OUT THE ACTION AND MESSAGE RECEIVED VIA SERIAL CONNECTION
// KEEP AN EYE OUT FOR THE transmitRFsignal ACTION
void triggerBedroomAction(String requestedRoom, String requestedAction) {
   if (requestedRoom == mqtt_room2_fan_action_topic && requestedAction == "1") {
    Serial.print("Setting ");
    Serial.print(bedroom2_alias);
    Serial.println("'s fan speed to low!");
        {
        for (a = 0; a < 8; a++) {
        for (int i = 0; i < sizeof(recordedSignal_fanlow2) - 1; i++) {
        digitalWrite(transmitter_pin, recordedSignal_fanlow2[i]);
        delayMicroseconds(393.9);
        }
        delayMicroseconds(9000);  }
        delay(800);
        }
      client.publish(mqtt_room2_fan_status_topic, "1");
  }
  else if (requestedRoom == mqtt_room2_fan_action_topic && requestedAction == "2") {
    Serial.print("Setting ");
    Serial.print(bedroom2_alias);
    Serial.println("'s fan speed to medium!");
        {
        for (a = 0; a < 8; a++) {
        for (int i = 0; i < sizeof(recordedSignal_fanmed2) - 1; i++) {
        digitalWrite(transmitter_pin, recordedSignal_fanmed2[i]);
        delayMicroseconds(393.9);
        }
        delayMicroseconds(9000);
        }
        delay(800);
        }
      client.publish(mqtt_room2_fan_status_topic, "2");
  }
  else if (requestedRoom == mqtt_room2_fan_action_topic && requestedAction == "3") {
    Serial.print("Setting ");
    Serial.print(bedroom2_alias);
    Serial.println("'s fan speed to high!");
        {
        for (a = 0; a < 8; a++) {
        for (int i = 0; i < sizeof(recordedSignal_fanhigh2) - 1; i++) {
        digitalWrite(transmitter_pin, recordedSignal_fanhigh2[i]);
        delayMicroseconds(393.9);
        }
        delayMicroseconds(9000);
        }
        delay(800);
        }
      client.publish(mqtt_room2_fan_status_topic, "3");
  }
  else if (requestedRoom == mqtt_room2_fan_action_topic && requestedAction == "0") {
    Serial.print("Setting ");
    Serial.print(bedroom2_alias);
    Serial.println("'s fan off!");
        {
        for (a = 0; a < 8; a++) {
        for (int i = 0; i < sizeof(recordedSignal_fanoff2) - 1; i++) {
        digitalWrite(transmitter_pin, recordedSignal_fanoff2[i]);
        delayMicroseconds(393.9);
        }
        delayMicroseconds(9000);
        }
        delay(800);
        }
      client.publish(mqtt_room2_fan_status_topic, "0");
  }
  else if (requestedRoom == mqtt_room2_light_action_topic && requestedAction == "off") {
    Serial.print("Changing ");
    Serial.print(bedroom2_alias);
    Serial.println("'s light status!");
        {
        for (a = 0; a < 8; a++) {
        for (int i = 0; i < sizeof(recordedSignal_lightoffon2) - 1; i++) {
        digitalWrite(transmitter_pin, recordedSignal_lightoffon2[i]);
        delayMicroseconds(393.9);
        }
        delayMicroseconds(9000);
        }
        delay(600);
        }
      client.publish(mqtt_room2_light_status_topic, "off");
  }
  else if (requestedRoom == mqtt_room2_light_action_topic && requestedAction == "on") {
    Serial.print("Changing ");
    Serial.print(bedroom2_alias);
    Serial.println("'s light status!");
        {
        for (a = 0; a < 8; a++) {
        for (int i = 0; i < sizeof(recordedSignal_lightoffon2) - 1; i++) {
        digitalWrite(transmitter_pin, recordedSignal_lightoffon2[i]);
        delayMicroseconds(393.9);
        }
        delayMicroseconds(9000);
        }
        delay(600);
        }
    client.publish(mqtt_room2_light_status_topic, "on");  
  }  
  else { Serial.println("Unrecognized action payload... taking no action!");
 }
}
//ENDS THE ACTION OF WRITING IN SERIAL WHAT WAS RECEIVED AND WHAT IT WAS TOLD TO DO



// Function that runs in loop() to connect/reconnect to the MQTT broker, and publish the current door statuses on connect

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(mqtt_clientId, mqtt_username, mqtt_password, availabilityTopic, 0, true, lwtMessage)) {
      Serial.println("Connected!");

      // Publish the birth message on connect/reconnect
      publish_birth_message();

      // Subscribe to the action topics to listen for action messages
      Serial.print("Subscribing to ");
      Serial.print(mqtt_room2_fan_action_topic);
      Serial.println("...");
      client.subscribe(mqtt_room2_fan_action_topic);
      Serial.print("Subscribing also to ");
      Serial.print(mqtt_room2_light_action_topic);
      Serial.println("...");
      client.subscribe(mqtt_room2_light_action_topic);    
      Serial.println("I am all subscribed.");


    } 
    else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}



void setup() {
  // Setup the output and input pins used in the sketch
  // Set the lastStatusValue variables to the state of the status pins at setup time

  // Setup Door 1 pins
  pinMode(transmitter_pin, OUTPUT);

  // Setup serial output, connect to wifi, connect to MQTT broker, set MQTT message callback

  Serial.begin(115200);
  delay(2);
  Serial.println("Starting RF transmitter for Hunter Fans...");
  setup_wifi();
  client.setServer(mqtt_broker, 1883);
  client.setCallback(callback);
}

void loop() {
  // Connect/reconnect to the MQTT broker and listen for messages
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
}

fan.yaml :

  - platform: mqtt  
    name: "Guest Bedroom 2 Fan"  
    state_topic: "bedroom/fan/2/FanSpeed"
    speed_state_topic: "bedroom/fan/2/FanSpeed"
    state_value_template: >
      {% if value_json.FanSpeed is defined %}
        {% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}
      {% else %}
        {% if states.fan.guest_bedroom_2_fan.state == 'off' -%}0{%- elif states.fan.guest_bedroom_2_fan.state == 'on' -%}4{%- endif %}
      {% endif %}
    speed_value_template: "{{ value_json.FanSpeed }}"
    availability:
      - topic: "RF_Transmitter/availability"
    payload_available: Online
    payload_not_available: Offline
    speed_command_topic: "bedroom/fan/2/FanSpeed"
    payload_low_speed: "1"
    payload_medium_speed: "2"
    payload_high_speed: "3"
    command_topic: "bedroom/fan/2/FanSpeed"
    payload_off: "0"
    payload_on: "4"
    qos: 0
    retain: false
    speeds:
      - off
      - low
      - medium
      - high

I know you’re going to point out that my status topci doesn’t quite align with conventional coding too, I changed this to “…/RESULT” as well in my testing. I’m open to any suggestions, I just wanted to point out I am aware the status topic matches the action topic.

The ‘off’ button does not seem to send any command to the wemos; no payload is sent over MQTT.
Also the buttons still don’t seem to change upon changing fan speed.
Seen here in this image, I’ve selected “M” or payload 2:

And the serial output from hitting button “M” (payload 2):
serialoutput

Payloads are all being received, and I can confirm that the publish is working, as you can see that the light status changes.
In the following image, I have clicked on all buttons, changing the status (including the off button).

I guess one of my questions also is "what is the necessity for payload 4?

EDIT: I found your thread trying to work out your jinja:

How does this implement into the TASMOTA fans? My fan’s remote only has 5 buttons:
Low
Medium
High
Off
Light (off/on)

I changed the speed state topic to match the javascript “FanSpeed” also to try to narrow down the issue/solution.
I’m not real strong in javascript but I imagine the js in the fan.yaml, says that any FanSpeed payload higher than 0 should change the icon color status.
I imagine in your fan-control-entity-row.js it says that if the button is pressed, the color of the button changes too, but that doesn’t seem to work for me.

Should I be publishing payload 4 in addition to any of my fan speeds 1,2,3?
Would that tell the card that the fan is on?

EDIT: I tried publishing payload 4 as well at the same time, this was a novice experimet, but I now believe I understand what you were achieving in your jinja code (I found an old link you were working on in 2018)

oops, I forgot to mention that I do have an ‘else’ statement that should serial print if it receives a payload it is not familiar with.

Any help or instruction greatly appreciated! I’m just trying to get this to work like you have and I think there may be some things still I don’t quite fully understand that are influencing my unexpected results.

something seems to be aloof. Maybe it is because I’m on the latest “greatest” version of HA.
I just tried to change your fan-control-entity-row.js file to a random color purple… nothing has changed.
Cleared my cache, full restart of HA installation, incognito mode, and I can’t see the color change…
Has anyone else been successful with this card at the latest HA version? Seems weird since the buttons work…but the customization is off.

Do I need anything in my configuration.yaml file other than the below:

hacs:
  token: !secret HACS_github
  appdaemon: true
  python_script: true
  theme: true
  sidepanel_title: HACS
  sidepanel_icon: mdi:store
  options:
    experimental: true 

What is the difference in these two addresses?
/hacsfiles/fan-control-entity-row/fan-control-entity-row.js
/config/www/community/fan-control-entity-row/fan-control-entity-row.js

I used HACS to install the fan-control-entity-row.js card, and it made for me the www/community/… address.
When I go into Configuration >> Lovelace Dashboard I am presented with an address that is different.

lovelacedashboard_resources

also, if I go to my url, for example, https://my_HA_address.duckdns.org/hacsfiles/fan-control-entity-row/fan-control-entity-row.js I see the original javascript document, unchanged. All of the color changes I made are default…
I’m perplexed at how this is running.

@finity
ISSUE FIXED!

I went to the thread from 2018 and was reading through your conversation.
I realized Graham (gpbenton) was able to publish to the RESULT topic the ‘{“FanSpeed”:4}’ payload which turned on the fan icon. I tried this too, and it worked for me which made me realize that specific payload is needed to be received.

I went back to my Wemos Code and added the following listed below.
It took me a little bit to learn how to send quotes as a variable, but once done, it works as designed (mostly).

const char* FanResult0 = "{\"FanSpeed\":0}";
const char* FanResult1 = "{\"FanSpeed\":1}";
const char* FanResult2 = "{\"FanSpeed\":2}";
const char* FanResult3 = "{\"FanSpeed\":3}";

  else if (requestedRoom == mqtt_room2_fan_action_topic && requestedAction == "3") {
    Serial.print("Setting ");
    Serial.print(bedroom2_alias);
    Serial.println("'s fan speed to high!");
      client.publish(mqtt_room2_fan_status_topic, "3");


------------------>  client.publish(mqtt_room2_fan_status_topic, FanResult3);


        {
        for (a = 0; a < 8; a++) {
        for (int i = 0; i < sizeof(recordedSignal_fanhigh2) - 1; i++) {
        digitalWrite(transmitter_pin, recordedSignal_fanhigh2[i]);
        delayMicroseconds(393.9);
        }
        delayMicroseconds(9000);
        }
        delay(800);
        }
  }

I don’t really care too much about changing the colors of the buttons as I kinda like the default view, but it does make me wonder where really I need to edit, in order for the changes to take place.

fancard

I’m glad you got it working.

The funny thing is I was working on a (long-ish) post that was going to point out to you that your code only provides a simple payload but the templates require a valid json object to decode (which is where the “value_json” comes into play). But I got called away for my real job and now that I’m back again I see you figured it out on your own. :+1:

If you want to try to get the colors working for future use then could you please post your latest card/row config in which you tried to change the colors?

I had this working great until the 0.115 update. Is there a new way make this work with the changes to templates?

What about the changes in templates caused this to stop working?

entity_id is no longer supported

I thought that breaking change was re: template sensors?
I’m on 0.115.5 and my fan template is still working.

I’ve looked at that template fan and I have to say looking at it again I’m really confused…

is there some reason why all of the entities in the fan template are referring to light entities? :man_shrugging:

However, either way, I’m not sure that having a value template and an entity_id was ever truly supported in the set_speed: section…? :man_shrugging:

I’m assuming he quoted my template post from earlier because he’s using the same product, the Inovelli LZW36 is a Z-Wave combo switch that is intended to control a fan and a light (single physical device, multiple endpoints). After it’s included to OZW both physical switch controls appear as lights. There’s no way to have OZW include it as a fan (I can’t remember if OZW 1.4 even includes fan support), so template out the light as a fan with certain brightness settings being equivalent to speed settings. You could control it as as a light entity but makes way more sense to interact with it as a fan entity.

1 Like

Ah, OK that makes sense now.

Thanks

Hey @Scott_C, I’m also trying to customise this card and seeing the same ‘cached?!?’ results after many restarts, clears etc.

Did you ever stumble upon a magical way to get the new code to come through… quickly?

Cheers,

Linton

Hello everybody! I am new to HA and feel like Alice in Wonderland. I use a new PI4, and am still much confused. Have some rusted experience with programming in C, and this is all very complicated to me, severe lack of knowledge…

My plan is to add my ceiling fan to HA. It is a simple fan with an IR remote. 4 buttons, for ‘off’, and speed 1,2 or 3. Installed a broadlink RM4 infrared transmitter. Learned the 4 buttons of the remote.

Installed the javascript, and I made a card that shows the 4 buttons. So far, so good. Now I have to connect the buttons to the fan - and I am totally stuck now.

My card looks like this now:

type: entities
show_header_toggle: false
entities:
  - entity: fan.sunroom_fan
    type: 'custom:fan-control-entity-row'
    name: MBR Fan Not Custom
    customTheme: true
    customOffText: UIT

In configuration.yaml I tried to paste the entire fan code, but when checking it for validity, I get complaints of all sorts. So I started with a small portion of it, that looks like this:

fan:
  - platform: template
    fans:
      sunroom_fan:
        friendly_name: "Sunroom Fan"
        value_template: "{{ states('input_boolean.sunroom_fan_state') }}"
        turn_on:
            service: remote.send_command
            data:
              entity_id: remote.broadlinkrm4_remote
              device: ventilator
              command: s1
        turn_off:
            service: remote.send_command
            data:
              entity_id: remote.broadlinkrm4_remote
              device: ventilator
              command: uit
        set_speed:
 
        speeds:
          - off
          - low
          - medium
          - high

When I click on the text MBR Fan not Custom, I get a panel with a switch, which in fact turns on my fan. The switch moves back to off, by itself, and when I click it again, the fan turns off. Wow!

Now I try to expand the code, adding the next bit:

- input_select:
      sunroom_fan_speed:
    name: Sunroom Fan Speeds
    options:
      - 'off'
      - 'low'
      - 'medium'
      - 'high'

This validates in the HA file editor, so I can save it.

But when checking the validity before restarting HA, I get this error:

Invalid config for [fan]: required key not provided @ data[‘platform’]. Got None. (See /config/configuration.yaml, line 50).

Line 50 is in fact the line where my fan: starts.

I have no clue what to do…
Any ideas?

Thanks in advance,
Frank

Do you have all of the fan configuration stuff directly in your configuration.yaml file or is it split into different files?

I see in your input select code that you have a dash (-) in front of the “input_select:” that shouldn’t be there and the indentation is way off for the second line. Is that a copy/paste error? Fix those first.

1 Like

I have it all in configuration.yaml
In the editor I fiddle with identations and dashes until it gives the green light, then save it, and check it for validity in the settings. Right now I changed it to this, which is fine in the editor, but not ok when I check it:

fan:
  - platform: template
    fans:
      sunroom_fan:
        friendly_name: "Sunroom Fan"
        value_template: "{{ states('input_boolean.sunroom_fan_state') }}"
        turn_on:
            service: remote.send_command
            data:
              entity_id: remote.broadlinkrm4_remote
              device: ventilator
              command: s1
        turn_off:
            service: remote.send_command
            data:
              entity_id: remote.broadlinkrm4_remote
              device: ventilator
              command: uit
        set_speed:
 
        speeds:
          - off
          - low
          - medium
          - high
          
        input_select:
            sunroom_fan_speed:
            name: Sunroom Fan Speeds
            options:
               - 'off'
               - 'low'
               - 'medium'
               - 'high'

Gives this error:

invalid config for [fan.template]: [input_select] is an invalid option for [fan.template]. Check: fan.template->fans->sunroom_fan->input_select. (See ?, line ?).

A big problem for me is right now that I honestly don’t know what I am doing and don’t know when and why I need to indent or apply dashes. But I’m good at copying and pasting :wink: Must be terrible for you all to see folks struggling with what should be obvious. Tried to find some tutorial texts to educate myself, but that is a challenge too…

Thanks for your time!