Smart Home Automation Forum
Tuya adapter V2 arduino source code - RS485 1 phase AC Energy Meter - Printable Version

+- Smart Home Automation Forum (https://www.kincony.com/forum)
+-- Forum: Technical Support (https://www.kincony.com/forum/forumdisplay.php?fid=20)
+--- Forum: KC868-ATC / Tuya adapter V2 (https://www.kincony.com/forum/forumdisplay.php?fid=32)
+--- Thread: Tuya adapter V2 arduino source code - RS485 1 phase AC Energy Meter (/showthread.php?tid=5705)



Tuya adapter V2 arduino source code - RS485 1 phase AC Energy Meter - admin - 05-08-2024

let your own RS485 AC energy meter work with Tuya app, so that can remote monitor meter data by Tuya app via internet.
   
   
   
   
arduino source code donwload: 
.zip   Tuya_AdapterV2_RS485_Energy_Meter.zip (Size: 2.41 KB / Downloads: 75)
Code:
#include <ModbusMaster.h>
#include <Arduino.h>
#include <TuyaWifi.h>
#include "HardwareSerial.h"
//---------RS485 setting
#define DEBUG   1

#define SERIAL_BAUD   9600
#define RX_PIN    32
#define TX_PIN    33
#define SERIAL_NUM  2
#define SLAVE_ADDR  225
//#define READ_ADDR  0
#define READ_NUM   2 

uint8_t raw_vcp_data[8] = {0};
uint16_t total_energy = 0;

uint16_t READ_ADDR = 0;
const static uint16_t addr_start_arr[6] = {
  0,100,106,118,142,144,
};
const static String emeter_name_arr[6] = {
  "Total active energy",
  "Voltage",
  "Current",
  "Active power",
  "Power factor",
  "Grid frequency",
};

typedef struct
{
  float total_active_energy;
  float voltage;
  float current;
  float active_power;
  float power_factor;
  float grid_freq;
}EMETER_STR;
typedef union
{
  EMETER_STR emeter_str;
  float emeter_arr[6];
}EMETER_UNION;

/* Current device DP values */
EMETER_UNION emeter_union = {0};

HardwareSerial My485Serial(SERIAL_NUM);
ModbusMaster node;
uint16_t rcv_buf[READ_NUM] = {0};
uint16_t conv_buf[READ_NUM] = {0};

static int16_t cnt_read = 0;

static void ReadEmeterRegs(void)
{
  uint32_t read_tmp = 0;
 
  READ_ADDR = addr_start_arr[cnt_read];
  uint8_t result = node.readHoldingRegisters(READ_ADDR, READ_NUM);
  if (result == node.ku8MBSuccess) {//if communicate successful then
       
    for (uint8_t j = 0; j < READ_NUM; j++)
    {
      rcv_buf[j] = node.getResponseBuffer(j);     
    }
    conv_buf[1] = rcv_buf[0];
    conv_buf[0] = rcv_buf[1];
    emeter_union.emeter_arr[cnt_read] = *(float*)&conv_buf[0];
    switch(cnt_read)
    {
      case 0:total_energy = emeter_union.emeter_arr[cnt_read] * 10;break;
      case 1:
        read_tmp = emeter_union.emeter_arr[cnt_read] * 10;
        raw_vcp_data[0] = (read_tmp &0xff00)>>8;
        raw_vcp_data[1] = (read_tmp &0x0ff);
        break;
      case 2:
        read_tmp = emeter_union.emeter_arr[cnt_read] * 1000;
        raw_vcp_data[2] = (read_tmp &0x0ff0000)>>16;
        raw_vcp_data[3] = (read_tmp &0x0ff00)>>8;
        raw_vcp_data[4] = read_tmp &0x0ff;
        break;
      case 3:
        read_tmp = emeter_union.emeter_arr[cnt_read] * 1000;
        raw_vcp_data[5] = (read_tmp &0x0ff0000)>>16;
        raw_vcp_data[6] = (read_tmp &0x0ff00)>>8;
        raw_vcp_data[7] = read_tmp &0x0ff;
        break;
      default:break;
    }
    #if DEBUG
    Serial1.print(emeter_name_arr[cnt_read]);
    Serial1.print(":<HEX 0x");
    Serial1.print(rcv_buf[0],HEX);
    Serial1.print(" ");
    Serial1.print(rcv_buf[1],HEX);
    Serial1.print(" FVALUE ");
    Serial1.print(emeter_union.emeter_arr[cnt_read]);
    Serial1.println("> ");
    #endif
    cnt_read++;
    if(cnt_read>=4) cnt_read = 0;
  }
  else
  {
    node.clearResponseBuffer();
  }
}

//---RS485 setting end----

TuyaWifi my_device;



/* Current LED status */
unsigned char led_state = 0;
/* Connect network button pin */
int key_pin = 25;


/* Data point define */
typedef enum
{
  DPID_TOTAL_ENERGY = 1,
  //DPID_VOLTAGE,
  //DPID_CURRENT,
  //DPID_ACTIVE_POWER,
  DPID_VCP = 6,
  //DPID_POWER_FACTOR,
  //DPID_GRID_FREQ,
}EMETER_DPID_DEF;


#define LED_WiFi  26
//#define LED_User  33



/* Stores all DPs and their types. PS: array[][0]:dpid, array[][1]:dp type.
*                                     dp type(TuyaDefs.h) : DP_TYPE_RAW, DP_TYPE_BOOL, DP_TYPE_VALUE, DP_TYPE_STRING, DP_TYPE_ENUM, DP_TYPE_BITMAP
*/
unsigned char dp_array[][2] =
{
  {DPID_TOTAL_ENERGY, DP_TYPE_VALUE},
  {DPID_VCP, DP_TYPE_RAW},
};

unsigned char pid[] = {"gl3gvyksva54unam"}; ////change pid here....
unsigned char mcu_ver[] = {"1.0.0"};

/* last time */
unsigned long last_time = 0;

void setup()
{

  My485Serial.begin(SERIAL_BAUD, SERIAL_8E1, RX_PIN, TX_PIN); //RS485 serial port
  node.begin(SLAVE_ADDR,My485Serial);
  Serial.begin(9600,SERIAL_8N1,22,19);  //Tuya module serial port
  Serial1.begin(115200,SERIAL_8N1,3,1);   //USB serial port

 
  // Serial with tuyawifi
 
 

  //Initialize led port, turn off led.
  pinMode(LED_WiFi, OUTPUT);
  digitalWrite(LED_WiFi, LOW);

/*  pinMode(LED_User, OUTPUT);
  digitalWrite(LED_User, LOW);*/

  //Initialize networking keys.
  pinMode(key_pin, INPUT_PULLUP);

  //Enter the PID and MCU software version
  my_device.init(pid, mcu_ver);
  //incoming all DPs and their types array, DP numbers
  my_device.set_dp_cmd_total(dp_array, 2);
  //register DP download processing callback function
  my_device.dp_process_func_register(dp_process);
  //register upload all DP callback function
  my_device.dp_update_all_func_register(dp_update_all);
 
  //delay(300);
  last_time = millis();
}

void loop()
{
  ReadEmeterRegs();  // read RS485 sensor
  my_device.uart_service();

  //Enter the connection network mode when Pin7 is pressed.
  if (digitalRead(key_pin) == LOW) {
    delay(80);
    if (digitalRead(key_pin) == LOW) {
      my_device.mcu_set_wifi_mode(SMART_CONFIG);
    }
  }
  /* LED blinks when network is being connected */
  if ((my_device.mcu_get_wifi_work_state() != WIFI_LOW_POWER) && (my_device.mcu_get_wifi_work_state() != WIFI_CONN_CLOUD) && (my_device.mcu_get_wifi_work_state() != WIFI_SATE_UNKNOW)) {
    if (millis()- last_time >= 500) {
      last_time = millis();

      if (led_state == LOW) {
        led_state = HIGH;
      } else {
        led_state = LOW;
      }
      digitalWrite(LED_WiFi, led_state);
    }
  }

  /* report the temperature and humidity */
  if ((my_device.mcu_get_wifi_work_state() == WIFI_CONNECTED) ||
      (my_device.mcu_get_wifi_work_state() == WIFI_CONN_CLOUD)) {
    dp_update_all();
  }

  delay(1000);
}

/**
* @description: DP download callback function.
* @param {unsigned char} dpid
* @param {const unsigned char} value
* @param {unsigned short} length
* @return {unsigned char}
*/
unsigned char dp_process(unsigned char dpid,const unsigned char value[], unsigned short length)
{
  /* all DP only report */
  return TY_SUCCESS;
}

/**
* @description: Upload all DP status of the current device.
* @param {*}
* @return {*}
*/
void dp_update_all(void)
{
  my_device.mcu_dp_update((unsigned char)DPID_TOTAL_ENERGY, total_energy, 1);
  my_device.mcu_dp_update((unsigned char)DPID_VCP, raw_vcp_data, 8);
}