Skip to content

Commit

Permalink
Merge pull request letscontrolit#5248 from tonhuisman/feature/P140-ad…
Browse files Browse the repository at this point in the history
…d-cardkb-i2c-keyboard

[P140] Add CardKB I2C Keyboard
  • Loading branch information
TD-er authored Feb 17, 2025
2 parents 4ad2038 + a4a38b3 commit ce2d13e
Show file tree
Hide file tree
Showing 14 changed files with 540 additions and 3 deletions.
110 changes: 110 additions & 0 deletions docs/source/Plugin/P140.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
.. include:: ../Plugin/_plugin_substitutions_p14x.repl
.. _P140_page:

|P140_typename|
==================================================

|P140_shortinfo|

Plugin details
--------------

Type: |P140_type|

Name: |P140_name|

Status: |P140_status|

GitHub: |P140_github|_

Maintainer: |P140_maintainer|

Used libraries: |P140_usedlibraries|

Description
-----------

M5Stack CardKB I2C ASCII input keyboard support.

Can be used to enter commands as if typing via USB serial to the device. It can also be used as input for a GUI, built using the AdaGFX_helper graphics commands, or a menu/button configuration via the Extended Touch panel, by handling the ``Key`` values in Rules.

Only printable ASCII characters (a-z, A-Z, 0-9, space and punctuation) will be appended to the input buffer. The ``Del`` key can be used for corrections (backspace), and ``Enter`` to submit the input. Other keys can be handled in Rules if **Send event on keypress** is enabled.

Configuration
--------------

.. image:: P140_DeviceConfiguration.png
:alt: Device configuration

* **Name** A unique name should be entered here.

* **Enabled** The device can be disabled or enabled. When not enabled the device should not use any resources.

I2C Options
^^^^^^^^^^^^

The available settings here depend on the build used, and configuration options set. At least the **Force Slow I2C speed** option is available, but selections for the I2C Multiplexer can also be shown. For details see the :ref:`Hardware_page`

Device Settings
^^^^^^^^^^^^^^^^

* **Execute input as command**: When enabled (default: On), input typed on the keyboard will be executed as a command when the ``Enter`` key is pressed, and corrections can be made by using the ``Del`` key, working as Backspace. When disabled, input will not be stored in the buffer (unless **Accept input only** is enabled), but should be handled in Rules by enabling **Send event on keypress**. After pressing ``Enter`` the buffer will be cleared.

* **Accept input only**: When enabled, it will accept input up until ``Enter`` is pressed, and *will send events* as if **Send event on keypress** was enabled. The buffer will also be cleared. If **Execute input as command** is also enabled, the input *is* also processed as a command. This is usually not the desired combination.

* **Send event on keypress**: When enabled will generate events with the ASCII code for the key. If **Execute input as command** or **Accept input only** are enabled, also the current buffer Length and Buffer content will be generated as events.

Buffer
^^^^^^

If the plugin is enabled, the **Current buffer content** is shown in this section. The value will *not* be automatically updated when adding or deleting characters to/from the buffer while the page is open.

.. image:: P140_BufferContentExample.png

Data Acquisition
^^^^^^^^^^^^^^^^

This group of settings, **Single event with all values** and **Send to Controller** settings are standard available configuration items. Send to Controller is only visible when one or more Controllers are configured.

**Interval** Is not available for this plugin, events will only be generated when the **Send event on keypress** setting is enabled, or **Accept input only** is enabled and ``Enter`` is pressed.

Values
^^^^^^

The current values are available in ``Key``, ``Length`` and ``Buffer``, limited to ``Key`` if **Execute input as command** and **Accept input only** are disabled. No decimals, formula or charting options are available.

To handle ``Buffer`` in Rules completely, the event handler has to be decorated with an asterisk, ``*``, to enable the possible non-numeric content of the buffer to be passed to the event handler:

.. code:: none
On CardKB#Buffer* Do
LogEntry,'CardKB: Current input buffer: %eventvalue1%'
Endon
When enabling **Single event with all values**, this is't needed, as the first event argument ``Key`` will always be numeric.

.. code:: none
On CardKB#All Do
LogEntry,'CardKB: Last key: %eventvalue1%, Length: %eventvalue2%, Input buffer: %eventvalue3%'
Endon
When **Execute input as command** is enabled, the current buffer content is shown in the Devices overview page:

.. image:: P140_DevicesOverviewExample.png

(The buffer content is only quoted when needed, so it can be passed as a single argument to event handlers.)

Commands
~~~~~~~~

.. include:: P140_commands.repl



Change log
----------

.. versionchanged:: 2.0

|added| 2025-02-08 Initially added.
Binary file added docs/source/Plugin/P140_BufferContentExample.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/Plugin/P140_DeviceConfiguration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions docs/source/Plugin/P140_commands.repl
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.. csv-table::
:header: "Command Syntax", "Extra information"
:widths: 20, 30

"
| ``CardKB,exec,<0|1>``
","
| Enable (``1``) or disable (``0``) the **Execute input as command** setting. Settings are not saved!
"
"
| ``CardKB,input,<0|1>``
","
| Enable (``1``) or disable (``0``) the **Accept input only** setting. Settings are not saved!
"
"
| ``CardKB,events,<0|1>``
","
| Enable (``1``) or disable (``0``) the **Send events on keypress** setting. Settings are not saved!
"
"
| ``CardKB,clear``
","
| Will clear the current content of the buffer.
"
1 change: 1 addition & 0 deletions docs/source/Plugin/_Plugin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ There are different released versions of ESP Easy:
":ref:`P137_page`","|P137_status|","P137"
":ref:`P138_page`","|P138_status|","P138"
":ref:`P139_page`","|P139_status|","P139"
":ref:`P140_page`","|P140_status|","P140"
":ref:`P141_page`","|P141_status|","P141"
":ref:`P142_page`","|P142_status|","P142"
":ref:`P143_page`","|P143_status|","P143"
Expand Down
2 changes: 1 addition & 1 deletion docs/source/Plugin/_plugin_categories.repl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
.. |Plugin_Gyro| replace:: :ref:`P045_page`, :ref:`P119_page`
.. |Plugin_Hardware| replace:: :ref:`P046_page`
.. |Plugin_Input| replace:: :ref:`P129_page` :ref:`P170_page`
.. |Plugin_Keypad| replace:: :ref:`P058_page`, :ref:`P061_page`, :ref:`P062_page`, :ref:`P063_page`
.. |Plugin_Keypad| replace:: :ref:`P058_page`, :ref:`P061_page`, :ref:`P062_page`, :ref:`P063_page` :ref:`P140_page`
.. |Plugin_Light_Color| replace:: :ref:`P050_page`, :ref:`P066_page`
.. |Plugin_Light_UV| replace:: :ref:`P084_page`, :ref:`P107_page`, :ref:`P114_page`, :ref:`P133_page`
.. |Plugin_Light_Lux| replace:: :ref:`P010_page`, :ref:`P015_page`, :ref:`P074_page`, :ref:`P168_page`
Expand Down
13 changes: 13 additions & 0 deletions docs/source/Plugin/_plugin_substitutions_p14x.repl
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
.. |P140_name| replace:: :cyan:`CardKB I2C Keyboard`
.. |P140_type| replace:: :cyan:`Keypad`
.. |P140_typename| replace:: :cyan:`Keypad - CardKB I2C Keyboard`
.. |P140_porttype| replace:: `.`
.. |P140_status| replace:: :yellow:`ESP32`
.. |P140_github| replace:: P140_CardKB.ino
.. _P140_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P140_CardKB.ino
.. |P140_usedby| replace:: `.`
.. |P140_shortinfo| replace:: `M5Stack CardKB I2C Keyboard`
.. |P140_maintainer| replace:: `tonhuisman`
.. |P140_compileinfo| replace:: `.`
.. |P140_usedlibraries| replace:: `.`

.. |P141_name| replace:: :cyan:`PCD8544 Nokia 5110 LCD`
.. |P141_type| replace:: :cyan:`Display`
.. |P141_typename| replace:: :cyan:`Display - PCD8544 Nokia 5110 LCD`
Expand Down
5 changes: 5 additions & 0 deletions docs/source/Reference/Command.rst
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,11 @@ P139 :ref:`P139_page`

.. include:: ../Plugin/P139_commands.repl

P140 :ref:`P140_page`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. include:: ../Plugin/P140_commands.repl

P141 :ref:`P141_page`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
188 changes: 188 additions & 0 deletions src/_P140_CardKB.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
#include "_Plugin_Helper.h"
#ifdef USES_P140

// #######################################################################################################
// ########################### Plugin 140: Keypad - M5Stack CardKB I2C Keyboard ##########################
// #######################################################################################################

/** Changelog:
* 2025-02-08 tonhuisman: Change category to Keypad from Input
* Add 'Execute input as command' setting (default enabled)
* Add 'Accept input only' setting
* Show length and buffer content only in Devices overview if Execute command or Accept input setting(s) are enabled
* 2025-02-06 tonhuisman: Start plugin for M5Stack CardKB I2C mini keyboard
**/

/** Supported commands:
* cardkb,exec,<0|1> : disable/enable Execute input as command
* cardkb,input,<0|1> : disable/enable Accept input only
* cardkb,events,<0|1> : disable/enable Send event on keypress
* cardkb,clear : clear the current buffer content
**/

# define PLUGIN_140
# define PLUGIN_ID_140 140
# define PLUGIN_NAME_140 "Keypad - CardKB I2C Keyboard"
# define PLUGIN_VALUENAME1_140 "Key"
# define PLUGIN_VALUENAME2_140 "Length"
# define PLUGIN_VALUENAME3_140 "Buffer"

# include "./src/PluginStructs/P140_data_struct.h"

boolean Plugin_140(uint8_t function, struct EventStruct *event, String& string)
{
boolean success = false;

switch (function)
{
case PLUGIN_DEVICE_ADD:
{
auto& dev = Device[++deviceCount];
dev.Number = PLUGIN_ID_140;
dev.Type = DEVICE_TYPE_I2C;
dev.VType = Sensor_VType::SENSOR_TYPE_DUAL;
dev.ValueCount = 3;
dev.SendDataOption = true;
dev.HasFormatUserVar = true;

break;
}

case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_140);

break;
}

case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_140));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_140));
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_140));

break;
}

case PLUGIN_I2C_HAS_ADDRESS:
{
success = event->Par1 == P140_I2C_ADDR;
break;
}

# if FEATURE_I2C_GET_ADDRESS
case PLUGIN_I2C_GET_ADDRESS:
{
event->Par1 = P140_I2C_ADDR;
success = true;
break;
}
# endif // if FEATURE_I2C_GET_ADDRESS

case PLUGIN_SET_DEFAULTS:
{
P140_EXEC_COMMAND = 1;
ExtraTaskSettings.TaskDeviceValueDecimals[0] = 0;
ExtraTaskSettings.TaskDeviceValueDecimals[1] = 0;
break;
}

case PLUGIN_GET_DEVICEVALUECOUNT:
{
event->Par1 = (P140_EXEC_COMMAND || P140_GET_INPUT) ? 3 : 1; // Suppress Length & Buffer if no command is to be executed
success = true;
break;
}

case PLUGIN_GET_DEVICEVTYPE:
{
event->sensorType = (P140_EXEC_COMMAND || P140_GET_INPUT) ? Sensor_VType::SENSOR_TYPE_TRIPLE : Sensor_VType::SENSOR_TYPE_SINGLE;
success = true;
break;
}

case PLUGIN_WEBFORM_LOAD:
{
addFormCheckBox(F("Execute input as command"), F("exec"), P140_EXEC_COMMAND == 1);

addFormCheckBox(F("Accept input only"), F("input"), P140_GET_INPUT == 1);

addFormCheckBox(F("Send event on keypress"), F("events"), P140_SEND_EVENTS == 1);

P140_data_struct *P140_data = static_cast<P140_data_struct *>(getPluginTaskData(event->TaskIndex));
String buffer;

if ((nullptr != P140_data) && P140_data->getBufferValue(buffer)) {
addFormSubHeader(F("Buffer"));
addRowLabel(F("Current buffer content"));
addHtml(buffer);
}
success = true;
break;
}

case PLUGIN_WEBFORM_SAVE:
{
P140_SEND_EVENTS = isFormItemChecked(F("events")) ? 1 : 0;
P140_EXEC_COMMAND = isFormItemChecked(F("exec")) ? 1 : 0;
P140_GET_INPUT = isFormItemChecked(F("input")) ? 1 : 0;
success = true;
break;
}

case PLUGIN_INIT:
{
initPluginTaskData(event->TaskIndex, new (std::nothrow) P140_data_struct(event));
P140_data_struct *P140_data = static_cast<P140_data_struct *>(getPluginTaskData(event->TaskIndex));

success = (nullptr != P140_data);

break;
}

case PLUGIN_READ:
{
P140_data_struct *P140_data = static_cast<P140_data_struct *>(getPluginTaskData(event->TaskIndex));

success = (nullptr != P140_data) && P140_data->plugin_read(event);

break;
}

case PLUGIN_WRITE:
{
P140_data_struct *P140_data = static_cast<P140_data_struct *>(getPluginTaskData(event->TaskIndex));

success = (nullptr != P140_data) && P140_data->plugin_write(event, string);

break;
}

case PLUGIN_TEN_PER_SECOND:
{
P140_data_struct *P140_data = static_cast<P140_data_struct *>(getPluginTaskData(event->TaskIndex));

success = (nullptr != P140_data) && P140_data->plugin_ten_per_second(event);

break;
}

case PLUGIN_FORMAT_USERVAR:
{
if ((P140_EXEC_COMMAND || P140_GET_INPUT) && (2 == event->idx)) { // Only Buffer is user-formatted
P140_data_struct *P140_data = static_cast<P140_data_struct *>(getPluginTaskData(event->TaskIndex));
String buffer;

if ((nullptr != P140_data) && P140_data->getBufferValue(buffer)) {
string = wrapWithQuotesIfContainsParameterSeparatorChar(buffer);
} else {
string = ' '; // Empty buffer indicator
}
}
break;
}
}
return success;
}

#endif // USES_P140
8 changes: 7 additions & 1 deletion src/src/CustomBuild/define_plugin_sets.h
Original file line number Diff line number Diff line change
Expand Up @@ -2440,7 +2440,7 @@ To create/register a plugin, you have to :
#define USES_P139 // AXP2101
#endif
#ifndef USES_P140
// #define USES_P140 //
#define USES_P140 // CardKB
#endif
#ifndef USES_P141
#define USES_P141 // PCD8544 Nokia 5110
Expand Down Expand Up @@ -2571,6 +2571,12 @@ To create/register a plugin, you have to :

#endif

#if !defined(USES_P140) && defined(ESP32) && !defined(UN_USES_P140) // Enabled for all ESP32, so we need a way to un-use
#define USES_P140
#endif
#if defined(UN_USES_P140) && defined(USES_P140)
#undef USES_P140
#endif

/******************************************************************************\
* Libraries dependencies *****************************************************
Expand Down
Loading

0 comments on commit ce2d13e

Please sign in to comment.