Thanks. I just skipped special char 2 & 3 and. Here's the result and the code:
Code: Select all
#ifdef USES_P012
//#######################################################################################################
//#################################### Plugin 012: LCD ##################################################
//#######################################################################################################
#include "_Plugin_Helper.h"
// Sample templates
// Temp: [DHT11#Temperature] Hum:[DHT11#humidity]
// DS Temp:[Dallas1#Temperature#R]
// Lux:[Lux#Lux#R]
// Baro:[Baro#Pressure#R]
// Pump:[Pump#on#O] -> ON/OFF
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C *lcd=NULL;
int Plugin_012_cols = 16;
int Plugin_012_rows = 2;
int Plugin_012_mode = 1;
#define PLUGIN_012
#define PLUGIN_ID_012 12
#define PLUGIN_NAME_012 "Display - LCD2004"
#define PLUGIN_VALUENAME1_012 "LCD"
#define P12_Nlines 4 // The number of different lines which can be displayed
#define P12_Nchars 80
boolean Plugin_012(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
static byte displayTimer = 0;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_012;
Device[deviceCount].Type = DEVICE_TYPE_I2C;
Device[deviceCount].VType = SENSOR_TYPE_NONE;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].FormulaOption = false;
Device[deviceCount].ValueCount = 0;
Device[deviceCount].SendDataOption = false;
Device[deviceCount].TimerOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_012);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_012));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
byte choice = PCONFIG(0);
//String options[16];
int optionValues[16];
for (byte x = 0; x < 16; x++)
{
if (x < 8)
optionValues[x] = 0x20 + x;
else
optionValues[x] = 0x30 + x;
//options[x] = F("0x");
//options[x] += String(optionValues[x], HEX);
}
addFormSelectorI2C(F("p012_adr"), 16, optionValues, choice);
byte choice2 = PCONFIG(1);
String options2[2];
options2[0] = F("2 x 16");
options2[1] = F("4 x 20");
int optionValues2[2] = { 1, 2 };
addFormSelector(F("Display Size"), F("p012_size"), 2, options2, optionValues2, choice2);
{
String strings[P12_Nlines];
LoadCustomTaskSettings(event->TaskIndex, strings, P12_Nlines, P12_Nchars);
for (byte varNr = 0; varNr < P12_Nlines; varNr++)
{
addFormTextBox(String(F("Line ")) + (varNr + 1), getPluginCustomArgName(varNr), strings[varNr], P12_Nchars);
}
}
addRowLabel(F("Display button"));
addPinSelect(false, F("taskdevicepin3"), CONFIG_PIN3);
addFormNumericBox(F("Display Timeout"), F("p012_timer"), PCONFIG(2));
String options3[3];
options3[0] = F("Continue to next line (as in v1.4)");
options3[1] = F("Truncate exceeding message");
options3[2] = F("Clear then truncate exceeding message");
int optionValues3[3] = { 0,1,2 };
addFormSelector(F("LCD command Mode"), F("p012_mode"), 3, options3, optionValues3, PCONFIG(3));
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
PCONFIG(0) = getFormItemInt(F("p012_adr"));
PCONFIG(1) = getFormItemInt(F("p012_size"));
PCONFIG(2) = getFormItemInt(F("p012_timer"));
PCONFIG(3) = getFormItemInt(F("p012_mode"));
char deviceTemplate[P12_Nlines][P12_Nchars];
String error;
for (byte varNr = 0; varNr < P12_Nlines; varNr++)
{
if (!safe_strncpy(deviceTemplate[varNr], web_server.arg(getPluginCustomArgName(varNr)), P12_Nchars)) {
error += getCustomTaskSettingsError(varNr);
}
}
if (error.length() > 0) {
addHtmlError(error);
}
SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
success = true;
break;
}
case PLUGIN_INIT:
{
if (PCONFIG(1) == 2) {
Plugin_012_rows = 4;
Plugin_012_cols = 20;
} else if (PCONFIG(1) == 1) {
Plugin_012_rows = 2;
Plugin_012_cols = 16;
}
Plugin_012_mode = PCONFIG(3);
//TODO:LiquidCrystal_I2C class doesn't have destructor. So if LCD type (size) is changed better reboot for changes to take effect.
// workaround is to fix the cols and rows at its maximum (20 and 4)
if (!lcd)
lcd = new LiquidCrystal_I2C(PCONFIG(0), 20, 4); //Plugin_012_cols, Plugin_012_rows);
// Setup LCD display
lcd->init(); // initialize the lcd
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GRUMPF
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
uint8_t tarrow[8] = {0x04,0x0E,0x1F,0x04,0x04,0x04,0x04,0x04};
uint8_t barrow[8] = {0x04,0x04,0x04,0x04,0x04,0x1F,0x0E,0x04};
uint8_t narrow[8] = {0x04,0x0E,0x1F,0x04,0x04,0x1F,0x0E,0x04};
uint8_t degc[8] = {0x08,0x14,0x08,0x03,0x04,0x04,0x04,0x03};
uint8_t degh[8] = {0x08,0x14,0x08,0x05,0x05,0x07,0x05,0x05};
uint8_t ms[8] = {0x1B,0x15,0x15,0x00,0x07,0x04,0x01,0x07};
lcd->createChar(0,tarrow);
lcd->createChar(1, narrow);
lcd->createChar(6, barrow); // 2 & 3 can't be display through HTTP command %2 or %3 bug ?
lcd->createChar(7, degc);
lcd->createChar(4, degh);
lcd->createChar(5, ms);
lcd->backlight();
lcd->setCursor(0,0);
lcd->print(F("ESP Easy Grumpf"));
lcd->setCursor(0,1);
for (int j=0; j<8; j++) {
lcd->write(j);}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
displayTimer = PCONFIG(2);
if (CONFIG_PIN3 != -1)
pinMode(CONFIG_PIN3, INPUT_PULLUP);
success = true;
break;
}
case PLUGIN_TEN_PER_SECOND:
{
if (CONFIG_PIN3 != -1)
{
if (!digitalRead(CONFIG_PIN3))
{
if (lcd) {
lcd->backlight();
}
displayTimer = PCONFIG(2);
}
}
break;
}
case PLUGIN_ONCE_A_SECOND:
{
if ( displayTimer > 0)
{
displayTimer--;
if (lcd && displayTimer == 0)
lcd->noBacklight();
}
break;
}
case PLUGIN_READ:
{
char deviceTemplate[P12_Nlines][P12_Nchars];
LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate));
for (byte x = 0; x < Plugin_012_rows; x++)
{
String tmpString = deviceTemplate[x];
if (lcd && tmpString.length())
{
String newString = P012_parseTemplate(tmpString, Plugin_012_cols);
lcd->setCursor(0, x);
lcd->print(newString);
}
}
success = false;
break;
}
case PLUGIN_WRITE:
{
String cmd = parseString(string, 1);
if (lcd && cmd.equalsIgnoreCase(F("LCDCMD")))
{
success = true;
String arg1 = parseString(string, 2);
if (arg1.equalsIgnoreCase(F("Off"))){
lcd->noBacklight();
}
else if (arg1.equalsIgnoreCase(F("On"))){
lcd->backlight();
}
else if (arg1.equalsIgnoreCase(F("Clear"))){
lcd->clear();
}
}
else if (lcd && cmd.equalsIgnoreCase(F("LCD")))
{
success = true;
int colPos = event->Par2 - 1;
int rowPos = event->Par1 - 1;
String text = parseStringKeepCase(string, 4);
text = P012_parseTemplate(text, Plugin_012_cols);
//clear line before writing new string
if (Plugin_012_mode == 2){
lcd->setCursor(colPos, rowPos);
for (byte i = colPos; i < Plugin_012_cols; i++) {
lcd->print(" ");
}
}
// truncate message exceeding cols
lcd->setCursor(colPos, rowPos);
if(Plugin_012_mode == 1 || Plugin_012_mode == 2){
lcd->setCursor(colPos, rowPos);
for (byte i = 0; i < Plugin_012_cols - colPos; i++) {
if(text[i]){
lcd->print(text[i]);
}
}
}
// message exceeding cols will continue to next line
else{
// Fix Weird (native) lcd display behaviour that split long string into row 1,3,2,4, instead of 1,2,3,4
boolean stillProcessing = 1;
byte charCount = 1;
while(stillProcessing) {
if (++colPos > Plugin_012_cols) { // have we printed 20 characters yet (+1 for the logic)
rowPos += 1;
lcd->setCursor(0,rowPos); // move cursor down
colPos = 1;
}
//dont print if "lower" than the lcd
if(rowPos < Plugin_012_rows ){
lcd->print(text[charCount - 1]);
}
if (!text[charCount]) { // no more chars to process?
stillProcessing = 0;
}
charCount += 1;
}
//lcd->print(text.c_str());
// end fix
}
}
break;
}
}
return success;
}
// Perform some specific changes for LCD display
// https://www.letscontrolit.com/forum/viewtopic.php?t=2368
String P012_parseTemplate(String &tmpString, byte lineSize) {
String result = parseTemplate_padded(tmpString, lineSize);
const char degree[3] = {0xc2, 0xb0, 0}; // Unicode degree symbol
const char degree_lcd[2] = {0xdf, 0}; // P012_LCD degree symbol
result.replace(degree, degree_lcd);
char unicodePrefix = 0xc3;
if (result.indexOf(unicodePrefix) != -1) {
// See: https://github.com/letscontrolit/ESPEasy/issues/2081
const char umlautAE_uni[3] = {0xc3, 0x84, 0}; // Unicode Umlaute AE
const char umlautAE_lcd[2] = {0xe1, 0}; // P012_LCD Umlaute
result.replace(umlautAE_uni, umlautAE_lcd);
const char umlaut_ae_uni[3] = {0xc3, 0xa4, 0}; // Unicode Umlaute ae
result.replace(umlaut_ae_uni, umlautAE_lcd);
const char umlautOE_uni[3] = {0xc3, 0x96, 0}; // Unicode Umlaute OE
const char umlautOE_lcd[2] = {0xef, 0}; // P012_LCD Umlaute
result.replace(umlautOE_uni, umlautOE_lcd);
const char umlaut_oe_uni[3] = {0xc3, 0xb6, 0}; // Unicode Umlaute oe
result.replace(umlaut_oe_uni, umlautOE_lcd);
const char umlautUE_uni[3] = {0xc3, 0x9c, 0}; // Unicode Umlaute UE
const char umlautUE_lcd[2] = {0xf5, 0}; // P012_LCD Umlaute
result.replace(umlautUE_uni, umlautUE_lcd);
const char umlaut_ue_uni[3] = {0xc3, 0xbc, 0}; // Unicode Umlaute ue
result.replace(umlaut_ue_uni, umlautUE_lcd);
const char umlaut_sz_uni[3] = {0xc3, 0x9f, 0}; // Unicode Umlaute sz
const char umlaut_sz_lcd[2] = {0xe2, 0}; // P012_LCD Umlaute
result.replace(umlaut_sz_uni, umlaut_sz_lcd);
}
return result;
}
#endif // USES_P012
Code: Select all
-- ~/domoticz/scripts/dzVents/KitchenTestClock.lua
-- Send text to LCD attached to a Wemos ESpeasy
return {
active = true,
on = {
timer = {'every minute'}
},
execute = function(domoticz)
local LCDSTR
----------------------------------------------------------------------------------------------------------
-- Script parameters EDIT HERE ***************************************************************************
----------------------------------------------------------------------------------------------------------
local Debug = "No"
local CustLCD ="Yes" -- Use Yes for custom LCD characters if you uploaded custom P012 LCD
local MyLCD ="http://172.19.0.221/control?cmd=LCD,"
local MySensor1 = "Room-Pergola" -- outside T & H
local MySensor2 = "Room-Kitchen" -- inside T
local MySensor3 = "Rain Accuweather" -- rain
local MySensor4 = "Wind Accuweather" -- wind
local MySensor5 = "Old Accuweather" -- Fake sensor for previous atmospheric pressure
local MyVar = "BarometricTendency" -- Global variable that store a Char (v,-,^)
----------------------------------------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------------------------------------
function DtoD(x)
local Winder = {"N","NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"}
local WinDex = math.floor(x/22.5+0.5)
--print(WinDex)
--print(Winder[WinDex])
return Winder[WinDex]
end
----------------------------------------------------------------------------------------------------------
-- Main CODE
----------------------------------------------------------------------------------------------------------
local outside = domoticz.devices(MySensor1)
local inside = domoticz.devices(MySensor2)
local Srain = domoticz.devices(MySensor3)
local SEwind = domoticz.devices(MySensor4)
local OPressure = domoticz.devices(MySensor5)
local STRG = DtoD(SEwind.direction)
local Btrend = domoticz.variables(MyVar).value
LCDSTR= MyLCD .."1,1,".. os.date("%A") .. "%A0" ..os.date("%d") .."%A0" .. os.date("%B")
os.execute('curl -s ' ..LCDSTR)
if CustLCD =="Yes" then
LCDSTR = MyLCD .."2,1,Out%A0" .. string.format("%.1f",outside.temperature) .."%07"
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."2,14,".. string.format("%.1f",outside.humidity) .."%04"
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD.. "3,1,In%A0%A0".. string.format("%.1f",inside.temperature) .."%07"
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."3,11,Rain%A0".. string.format("%.1f",Srain.rainRate) .."%20"
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."4,1,Wind%A0".. STRG
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."4,12,".. string.format("%.1f",SEwind.speed) .."%05"
os.execute('curl -s ' ..LCDSTR)
if Btrend == "^" then
LCDSTR= MyLCD .."4,20,%00"
elseif Btrend == "v" then
LCDSTR= MyLCD .."4,20,%06"
else
LCDSTR= MyLCD .."4,20,%01"
end
os.execute('curl -s ' ..LCDSTR)
else
LCDSTR = MyLCD .."2,1,Out%A0" .. string.format("%.1f",outside.temperature) .."%C2%B0C"
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."2,14,".. string.format("%.0f",outside.humidity) .."%H"
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD.. "3,1,In%A0%A0".. string.format("%.1f",inside.temperature) .."%C2%B0C"
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."3,12,Rain%A0".. string.format("%.1f",Srain.rainRate)
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."4,1,Wind%A0".. STRG
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."4,12,".. string.format("%.1f",SEwind.speed) .."m/s"
os.execute('curl -s ' ..LCDSTR)
LCDSTR= MyLCD .."4,20," .. Btrend
os.execute('curl -s ' ..LCDSTR)
end
if Debug=="Yes" then
domoticz.log('Temp is ' ..string.format("%.1f",TSensor.temperature))
domoticz.log('Humidity is ' ..string.format("%.1f",TSensor.humidity))
domoticz.log(LCDSTR)
end
end
}