├── LICENSE ├── README.md ├── SUMMARY.md ├── docker ├── docker-compose.yml └── redis.conf ├── readme ├── WagoSysDynamicIoMapping.md ├── blocking.md ├── connect.md ├── excists.md ├── get.md ├── hget.md ├── hgetall.md ├── hset.md ├── json.get.md ├── json.set.md ├── lpop.md ├── lpush.md ├── pipelining.md ├── psubscribe.md ├── publish.md ├── punsubscribe.md ├── rpush.md ├── set.md ├── subscriberBase.md ├── tsadd.md ├── tscreate.md ├── unsubscribe.md ├── xadd.md └── xread.md ├── redis-no-unixsocket.compiled-library └── redis.compiled-library /LICENSE: -------------------------------------------------------------------------------- 1 | LICENSE 2 | Version 1.1 April 2024. 3 | 4 | This compiled CODESYS library is currently under developement, and is only for evaluation purpose in test environments. 5 | The sourcecode of the library, if present, is not open source yet (in short terms meaning it's content is protected from being used, reproduced and distributed). 6 | 7 | Copyright (c) 2024 Kai Thorgrim Jansrud, Norway -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Redis Codesys client 3 | --- 4 | 5 | # redis-codesys-lib 6 | 7 | ## About 8 | 9 | [CoDeSys ](https://www.codesys.com/)client for [Redis, ](https://redis.io/)[KeyDB](https://docs.keydb.dev) and [DragonflyDB](https://www.dragonflydb.io/). Description how to install [here ](https://help.codesys.com/webapp/\_cds\_adding\_libraries\_to\_repository;product=codesys;version=3.5.17.0). 10 | 11 | ### CoDeSys 12 | 13 | Compiled in 3.5.20.40 14 | 15 | ## Supported commands 16 | 17 | * [CONNECT](readme/connect.md) 18 | * [GET](readme/get.md) 19 | * [SET](readme/set.md) 20 | * [HSET](readme/hset.md) 21 | * [HGET](readme/hget.md) 22 | * [HGETALL](readme/hgetall.md) 23 | * [LPUSH](readme/lpush.md) 24 | * [RPUSH](readme/rpush.md) 25 | * [LPOP](readme/lpop.md) 26 | * [PUBLISH](readme/publish.md) 27 | * [SUBSCRIBERBASE](readme/subscriberBase.md) 28 | * [UNSUBSCRIBE](readme/unsubscribe.md) 29 | * [PSUBSCRIBE](readme/psubscribe.md) 30 | * [PUNSUBSCRIBE](readme/punsubscribe.md) 31 | * [EXCISTS](readme/excists.md) 32 | * [JSON.SET](readme/json.set.md) 33 | * [JSON.GET](readme/json.get.md) 34 | * [XADD](readme/xadd.md) 35 | * [XREAD](readme/xread.md) 36 | * [TSCREATE](readme/tscreate.md) 37 | * [TSADD](readme/tsadd.md) 38 | 39 | ## CRG-Stack 40 | 41 | Stack can be installed with docker compose (docker-folder). Before you start, check paths in the docker compose file. 42 | 43 | Redis configuration: 44 | ``` 45 | wget -O redis.conf https://raw.githubusercontent.com/thorgrimjansrud/redis-codesys-lib/main/docker/redis.conf --no-check-certificate 46 | ``` 47 | Note: Seems like redis/redis-stack-server sends PCP (Performance Co-Pilot) on localhost:6379 so port is here changed to 9001. 48 | 49 | Compose file: 50 | ``` 51 | wget -O docker-compose.yml https://raw.githubusercontent.com/thorgrimjansrud/redis-codesys-lib/main/docker/docker-compose.yml --no-check-certificate 52 | ``` 53 | Socket access for Grafana: 54 | ``` 55 | sudo chmod ugo+rw /tmp/redis.sock 56 | ``` 57 | 58 | We can now connect to Redis UI on http://IP:5540 and configure database connection on 127.0.0.1:9001. 59 | Grafana is availible on http://IP:3000 with Redis datasource on unix socket. 60 | 61 | ## Examples 62 | 63 | * [WagoSysDynamicIoMapping](readme/WagoSysDynamicIoMapping.md) 64 | * [Pipelining](readme/pipelining.md) 65 | * [Blocking](readme/blocking.md) 66 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Table of contents 2 | 3 | * [redis-codesys-lib](README.md) 4 | -------------------------------------------------------------------------------- /docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | # "/redis.conf" must be updated to fit actual path in the device 3 | # Use Network_mode to communicate from Insight localhost (127.0.0.1) to Redis db. 4 | 5 | version: "3" 6 | 7 | services: 8 | redis-server: 9 | image: redis/redis-stack-server:latest 10 | container_name: redis-stack 11 | restart: always 12 | network_mode: host 13 | command: redis-stack-server --include /usr/local/etc/redis/redis.conf 14 | volumes: 15 | - /tmp:/tmp 16 | - redis:/data 17 | - /home/pi/redis/redis.conf:/usr/local/etc/redis/redis.conf 18 | 19 | redis-insight: 20 | image: redis/redisinsight:latest 21 | container_name: redisinsight 22 | restart: always 23 | network_mode: host 24 | ports: 25 | - '5540:5540' 26 | volumes: 27 | - redisinsight:/data 28 | 29 | #grafana: 30 | # image: grafana/grafana 31 | # container_name: grafana 32 | # restart: always 33 | # ports: 34 | # - '3000:3000' 35 | # volumes: 36 | # - /tmp:/tmp 37 | 38 | volumes: 39 | redis: 40 | redisinsight: 41 | -------------------------------------------------------------------------------- /docker/redis.conf: -------------------------------------------------------------------------------- 1 | # Change port from default 6397 to 9001. 2 | port 9001 3 | # bind to all interfaces. (127.0.0.1 for localhost only.) 4 | bind 0.0.0.0 5 | unixsocket /tmp/redis.sock 6 | unixsocketperm 755 -------------------------------------------------------------------------------- /readme/WagoSysDynamicIoMapping.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Gateway 3 | --- 4 | 5 | # Redis IO gateway 6 | 7 | ## Codesys usage 8 | 9 | Dynamic configuration and processing of IO modules. Add the library "WagoSysDynamicIoMapping". Set property "use dynamic memory allocation" for the project. 10 | Example provides a minimalistic, easy-to-understand picture of how to configure the dynamic setup of a digital module. Here we use the REDIS get command to 11 | set a digital output on a Wago 750-508 module: 12 | 13 | ``` 14 | PROGRAM PLC_PRG 15 | VAR 16 | RedisClient : FbRedis; 17 | Redis : IClient := RedisClient; 18 | xConnected, xTrigGet : BOOL; 19 | sResult, sKey: STRING; 20 | xTerminalManagerReady : BOOL; 21 | uiIdx: INT; 22 | uiSize: UINT; 23 | xInit: BOOL; 24 | wOutData: WORD; 25 | END_VAR 26 | ``` 27 | PLC_PRG 28 | ``` 29 | xConnected := Redis.connect(sServer:= '10.0.0.113', wPortNo:= 6379, xUnix:=FALSE); 30 | 31 | IF xConnected THEN 32 | PLC_PRG.IoGw(); 33 | sKey := 'module_1_750_508_ch1'; 34 | IF xTrigGet THEN 35 | sResult := Redis.Get(psKey:= ADR(sKey)); 36 | IF sResult <> '' THEN 37 | IF sResult = 'true' THEN 38 | wOutData := 1; 39 | ELSE 40 | wOutData := 0; 41 | END_IF 42 | xTrigGet := FALSE; 43 | END_IF 44 | END_IF 45 | END_IF 46 | ``` 47 | Action IoGw (PLC_PRG) 48 | ``` 49 | IF NOT xTerminalManagerReady THEN 50 | xTerminalManagerReady := DynIomanager.DynKbusIoManager.xIsInit; 51 | RETURN; 52 | END_IF 53 | 54 | IF NOT xInit THEN 55 | FOR uiIdx := 1 TO DynIomanager.DynKbusIoManager.coModules.uiModuleCount DO 56 | CASE DynIomanager.DynKbusIoManager.coModules.aIModules[uiIdx].eType OF 57 | WagoTypesBusServices.eTerminalType.DIGITAL_OUTPUT_DIAG: 58 | uiSize := DynIomanager.DynKbusIoManager.coModules.aIModules[uiIdx].GetModuleOutputSize(); 59 | END_CASE 60 | END_FOR 61 | xInit := TRUE; 62 | END_IF 63 | 64 | IF xInit THEN 65 | FOR uiIdx := 1 TO DynIomanager.DynKbusIoManager.coModules.uiModuleCount DO 66 | CASE DynIomanager.DynKbusIoManager.coModules.aIModules[uiIdx].eType OF 67 | WagoTypesBusServices.eTerminalType.DIGITAL_OUTPUT_DIAG: 68 | DynIoManager.DynKbusIoManager.coModules.aIModules[uiIdx].SetProcessOutData(pOutData:= ADR(wOutData), uiNOutData:= uiSize); 69 | END_CASE 70 | END_FOR 71 | END_IF 72 | ``` 73 | 74 | -------------------------------------------------------------------------------- /readme/blocking.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Blocking (v1.0.2.0) 3 | --- 4 | 5 | # Optimze redis calls with method blocking 6 | 7 | ## Codesys usage 8 | 9 | Default the library methods are non-blocking and will exit with or without any data. With blocking propterty you can 10 | let the library wait for reply messages. The timeout parameter is set in the parameter list. 11 | 12 | ``` 13 | VAR 14 | FbRedis : FbRedis; 15 | IBase : IBase := FbRedis; 16 | IClient : IClient := FBRedis; 17 | IRedisHelpers : IHelpers := FbRedis; 18 | sKey, sValue, sData : STRING(gcMAX_STRINGLENGHT); 19 | xSuccess : bool; 20 | eStatusCode : eStatusCode; 21 | typOptions : typSetOptions; 22 | END_VAR 23 | ``` 24 | 25 | ``` 26 | IRedisHelpers.BlockingMode := TRUE; 27 | 28 | sKey := 'lux'; 29 | sValue := '2000'; 30 | 31 | // SET 32 | eStatusCode := IClient.Set(psKey:= ADR(sKey), psValue:= ADR(sValue), ptypOptions:= ADR(typOptions), sRetVal:= sData); 33 | 34 | // GET 35 | eStatusCode := IClient.Get(psKey:= ADR(sKey), sRetVal:= sData); 36 | 37 | // Test 38 | if sData = sValue then 39 | xSuccess := true; 40 | end_if 41 | 42 | ``` 43 | 44 | ## Note 45 | 46 | Make sure you set the timeoutvalue correctly. This may need some tuning depending on your system. 47 | The blocking propterty will halt the program execution and increase cycle time. 48 | propterty -------------------------------------------------------------------------------- /readme/connect.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # CONNECT 6 | 7 | ## Codesys usage 8 | 9 | Connect to a remote Redis server at given IP or unix socket: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedisBase : IBase := FbRedis; 15 | typConnectStatus : typConnectStatus; 16 | sHost : STRING; 17 | wDefaultPort : WORD := 6379; 18 | END_VAR 19 | ``` 20 | ``` 21 | typConnectStatus := IRedisBase.connect(sHost:= sHost, wPortNo:= wDefaultPort); 22 | IF typConnectStatus.xConnected THEN 23 | ... 24 | END_IF 25 | ``` 26 | 27 | ## Note 28 | 29 | After each reset (soft and hard) and download of program Codesys will create a new socket descriptor (socket file descriptor is not retained in Codesys). 30 | A multiple of socket descriptors can thus be excisting in the system/OS. 31 | -------------------------------------------------------------------------------- /readme/excists.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # EXCISTS 6 | 7 | ## Codesys usage 8 | 9 | Checks if the keys excists or not: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger : BOOL; 16 | asKey : ARRAY [1..3] OF STRING(gcMAX_STRINGLENGHT); 17 | psResult : POINTER TO STRING(gcMAX_STRINGLENGHT); 18 | END_VAR 19 | ``` 20 | 21 | ``` 22 | IF xTrigger THEN 23 | psResult := IRedis.exists(asKey:= asKey); 24 | IF TO_INT(psResult^) > 0 THEN 25 | xTrigger := FALSE; 26 | END_IF 27 | END_IF 28 | ``` 29 | -------------------------------------------------------------------------------- /readme/get.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # GET 6 | 7 | ## Codesys usage 8 | 9 | Retrieves value from a key: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger : BOOL; 16 | sKey, sData : STRING(gcMAX_STRINGLENGHT); 17 | eStatusCode : eStatusCode; 18 | END_VAR 19 | ``` 20 | 21 | ``` 22 | IF xTrigger THEN 23 | eStatusCode := IClient.Get(psKey:= ADR(sKey), sRetVal:= sData); 24 | IF sData <> '' and eStatusCode = 0 THEN 25 | xTrigger := FALSE; 26 | END_IF 27 | END_IF 28 | ``` 29 | -------------------------------------------------------------------------------- /readme/hget.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # HGET 6 | 7 | ## Codesys usage 8 | 9 | Reads field and value stored at hash: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger : BOOL; 16 | sKey, sField, sData : STRING; 17 | eStatusCode : eStatusCode; 18 | END_VAR 19 | ``` 20 | 21 | ``` 22 | IF xTrigger THEN 23 | eStatusCode := IClient.Hget(psKey:= ADR(sKey), psField:= ADR(sField), sRetVal:= sData); 24 | IF sData <> '' and eStatusCode = 0 THEN 25 | xTrigger := FALSE; 26 | END_IF 27 | END_IF 28 | ``` 29 | -------------------------------------------------------------------------------- /readme/hgetall.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # HGETALL 6 | 7 | ## Codesys usage 8 | 9 | Reads all fields and values stored at hash: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger: BOOL; 16 | sKey : STRING; 17 | patypElements : pointer to array [1..gcMAX_ELEMENT] of atypElement; 18 | eStatusCode : eStatusCode; 19 | END_VAR 20 | ``` 21 | 22 | ``` 23 | IF xTrigger THEN 24 | eStatusCode := IClient.HgetAll(psKey:= ADR(sKey), atypElement:= atypElement); 25 | END_IF 26 | ``` 27 | -------------------------------------------------------------------------------- /readme/hset.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # HSET 6 | 7 | ## Codesys usage 8 | 9 | Write field and value stored at hash: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger : BOOL; 16 | sKey, sData : STRING; 17 | asField, asValue : ARRAY [1..gcMAX_HASH] OF STRING(gcMAX_STRINGLENGHT); 18 | eStatusCode : eStatusCode; 19 | END_VAR 20 | ``` 21 | 22 | ``` 23 | IF xTrigger THEN 24 | eStatusCode := IClient.Hset(psKey:= ADR(sKey), asField:= asFields, asValue:= asValues, sRetVal:= sData); 25 | IF sData <> '' and eStatusCode = 0 THEN 26 | xTrigger := FALSE; 27 | END_IF 28 | END_IF 29 | ``` 30 | 31 | 32 | -------------------------------------------------------------------------------- /readme/json.get.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # JSON.GET 6 | 7 | RedisJSON must be installed. 8 | 9 | ## Codesys usage 10 | 11 | Return the value at path in JSON serialized form: 12 | 13 | ``` 14 | VAR 15 | FbRedis : FbRedis; 16 | IRedis : IJson := FbRedis; 17 | xTrigger, xNX, xXX : BOOL; 18 | sKey, sRootPath : STRING; 19 | sValue : STRING(gcMAX_STRINGLENGHT); 20 | END_VAR 21 | ``` 22 | 23 | ``` 24 | IF xTrigger THEN 25 | psRetValue := IRedis.JsonGet(psKey:= ADR(sKey), psPath:= ADR(sPath), xIndent:= xIndent, xNewLine:= xNewLine, xSpace:= xSpace); 26 | IF psRetValue^ <> '' THEN 27 | xReadJson := FALSE; 28 | END_IF 29 | END_IF 30 | ``` 31 | 32 | ## Note sRootPath 33 | 34 | When a dollar sign '$' is in a string literal, the following two characters are interpreted as a hexadecimal code according to the coding in ISO/IEC 8859-1. This means $n$r is new line and linebreak. Two dollar '$$' is a dollar '$'. -------------------------------------------------------------------------------- /readme/json.set.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # JSON.SET 6 | 7 | RedisJSON must be installed. 8 | 9 | ## Codesys usage 10 | 11 | Set the JSON value at path in key: 12 | 13 | ``` 14 | VAR 15 | FbRedis : FbRedis; 16 | IRedis : IJson := FbRedis; 17 | xTrigger, xNX, xXX : BOOL; 18 | sResult, sKey, sRootPath : STRING; 19 | sValue : STRING(gcMAX_STRINGLENGHT); 20 | END_VAR 21 | ``` 22 | 23 | ``` 24 | IF xTrigger THEN 25 | sRootPath := '$$'; 26 | sResult := IRedis.JsonSet(psKey:= ADR(sKey),psPath:= ADR(sRootPath),psValue:= ADR(sValue),xNX:= xNX,xXX:= xXX); 27 | IF sResult <> '' THEN 28 | xTrigger := FALSE; 29 | END_IF 30 | END_IF 31 | ``` 32 | 33 | ## Note sRootPath 34 | 35 | When a dollar sign '$' is in a string literal, the following two characters are interpreted as a hexadecimal code according to the coding in ISO/IEC 8859-1. This means $n$r is new line and linebreak. Two dollar '$$' is a dollar '$'. 36 | 37 | -------------------------------------------------------------------------------- /readme/lpop.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # LPOP 6 | 7 | ## Codesys usage 8 | 9 | Removes and returns the first elements of the list stored at key: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger : BOOL; 16 | uiCount: uint; 17 | sKey : STRING; 18 | asElement : ARRAY [1..gcMAX_ELEMENT] OF STRING(gcMAX_STRINGLENGHT); 19 | eStatusCode : eStatusCode; 20 | END_VAR 21 | ``` 22 | 23 | ``` 24 | IF xTrigger THEN 25 | eStatusCode := IClient.LPop(psKey:= ADR(sKey), uiCount:= uiCount, asElement:= asElement); 26 | IF asElement[1] <> '' and eStatusCode = 0 THEN 27 | xTrigger := FALSE; 28 | END_IF 29 | END_IF 30 | ``` 31 | -------------------------------------------------------------------------------- /readme/lpush.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # LPUSH 6 | 7 | ## Codesys usage 8 | 9 | Insert specified values at the start of the list stored at key: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger : BOOL; 16 | sKey, sData : STRING; 17 | asElement : ARRAY [1..gcMAX_ELEMENT] OF STRING(gcMAX_STRINGLENGHT); 18 | eStatusCode : eStatusCode; 19 | END_VAR 20 | ``` 21 | 22 | ``` 23 | IF xTrigger THEN 24 | eStatusCode := FbRedis.LPush(psKey:= ADR(sKey) , asElement:= asElement, sRetVal:= sData); 25 | IF sData <> '' and eStatusCode = 0 THEN 26 | xTrigger := FALSE; 27 | END_IF 28 | END_IF 29 | ``` 30 | -------------------------------------------------------------------------------- /readme/pipelining.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Pipelining (v1.0.1.2) 3 | --- 4 | 5 | # Optimze round trip times with pipelining 6 | 7 | ## Codesys usage 8 | 9 | Redis pipelining is a technique for improving performance by issuing multiple commands at once without waiting for the response to each individual command. 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IBase : IBase := FbRedis; 15 | IClient : IClient := FBRedis; 16 | IPipe : IPipe := FbRedis; 17 | xIsPiped : BOOL; 18 | iAmount, iWaitingCycle: INT; 19 | sChannel, sMessage : STRING(gcMAX_STRINGLENGHT); 20 | asRetValue : ARRAY [1..gcMAX_ELEMENT] OF STRING(gcMAX_STRINGLENGHT); 21 | eStatusCode : eStatusCode; 22 | unRx : unRx; 23 | END_VAR 24 | ``` 25 | 26 | ``` 27 | // Amount of piped telegrams 28 | iAmount := 5; 29 | 30 | // Start pipe 31 | xIsPiped := IPipe.Pipeline(); 32 | 33 | // Data is i counter values. Wait until ready for new values. 34 | IF xWait THEN 35 | FOR i:=1 TO iAmount DO 36 | sChannel := 'counter'; 37 | sMessage := TO_STRING(iCounter); 38 | iCounter := iCounter + 1; 39 | // Buffer messages 40 | eStatusCode := IClient.Publish(psChannel:= ADR(sChannel), psMessage:= ADR(sMessage), asRetVal:= asRetValue); 41 | END_FOR 42 | END_IF 43 | 44 | // Execute pipe 45 | IPipe.Exec(asRetVal:= asRetValue); 46 | IF asRetValue[1] <> '' AND asRetValue[2] <> '' AND asRetValue[3] <> '' AND asRetValue[4] <> '' AND asRetValue[5] <> '' THEN 47 | xWait := false; 48 | ELSE 49 | xWait := true; 50 | END_IF 51 | ``` 52 | 53 | -------------------------------------------------------------------------------- /readme/psubscribe.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # PSUBSCRIBE 6 | 7 | ## Codesys usage 8 | 9 | Subscribes the client to the given patterns. Subscriber needs to run. Feedback in atypSubResult: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : ISubscriber := FbRedis; 15 | xSubConnected, xSubscribe, xPSubscribe : BOOL; 16 | asSubscriptions : ARRAY [1..gcMAX_SUBSCRIPTIONS] OF STRING(gcMAX_STRINGLENGHT); 17 | patypSubResult : pointer to typSubResults; 18 | END_VAR 19 | ``` 20 | 21 | ``` 22 | IF xSubConnected THEN 23 | patypSubResult := IRedis.SubscriberBase(asChannel:= asSubscriptions, xAddChannel:= xSubscribe); 24 | IRedis.PSubscribe(asChannel:= asSubscriptions, xTrigger:= xPSubscribe); 25 | END_IF 26 | ``` 27 | 28 | ## Note 29 | 30 | Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional SUBSCRIBE, SSUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, SUNSUBSCRIBE, PUNSUBSCRIBE, PING, RESET and QUIT commands. However, if RESP3 is used (see HELLO) it is possible for a client to issue any commands while in subscribed state. -------------------------------------------------------------------------------- /readme/publish.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # PUBLISH 6 | 7 | ## Codesys usage 8 | 9 | Posts a message to the given channel: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | asRetValue : ARRAY [1..gcMAX_ELEMENT] OF STRING(gcMAX_STRINGLENGHT); 16 | sPubChannel: STRING(gcMAX_STRINGLENGHT); 17 | sPubMessage: STRING(gcMAX_STRINGLENGHT); 18 | eStatusCode : eStatusCode; 19 | END_VAR 20 | ``` 21 | 22 | ``` 23 | 24 | eStatusCode := IClient.Publish(psChannel:= ADR(sChannel), psMessage:= ADR(sMessage), asRetVal:= asRetValue); 25 | IF asRetValue[1] <> '' AND eStatusCode = 0 THEN 26 | asRetValue[1] := ''; 27 | END_IF 28 | 29 | ``` 30 | 31 | ## Note 32 | 33 | Returns the number of clients that the message was sent to in ARRAY [1]. 34 | if message was piped, returns answer of [1..gcMAX_ELEMENT] that was piped. -------------------------------------------------------------------------------- /readme/punsubscribe.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # PUNSUBSCRIBE 6 | 7 | ## Codesys usage 8 | 9 | Unsubscribes the client from the given patterns, or from all of them if none is given. Subscriber needs to run. Feedback in atypSubResult: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : ISubscriber := FbRedis; 15 | xSubConnected, xPSubscribe, xPUnsubscribe: BOOL; 16 | asSubscriptions, asPUnsubscribe : ARRAY [1..gcMAX_SUBSCRIPTIONS] OF STRING(gcMAX_STRINGLENGHT); 17 | patypSubResult : pointer to typSubResults; 18 | END_VAR 19 | ``` 20 | 21 | ``` 22 | IF xSubConnected THEN 23 | patypSubResult := IRedis.SubscriberBase(asChannel:= asSubscriptions, xAddChannel:= xSubscribe); 24 | IRedis.PUnSubscribe(asChannel:= asPunsubscribe, xTrigger:= xPUnsubscribe); 25 | END_IF 26 | ``` 27 | 28 | ## Note 29 | 30 | Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional SUBSCRIBE, SSUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, SUNSUBSCRIBE, PUNSUBSCRIBE, PING, RESET and QUIT commands. However, if RESP3 is used (see HELLO) it is possible for a client to issue any commands while in subscribed state. -------------------------------------------------------------------------------- /readme/rpush.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # RPUSH 6 | 7 | ## Codesys usage 8 | 9 | Insert specified values at the end of the list stored at key: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger : BOOL; 16 | sKey, sData : STRING; 17 | asElement : ARRAY [1..gcMAX_ELEMENT] OF STRING(gcMAX_STRINGLENGHT); 18 | eStatusCode : eStatusCode; 19 | END_VAR 20 | ``` 21 | 22 | ``` 23 | IF xTrigger THEN 24 | eStatusCode := FbRedis.RPush(psKey:= ADR(sKey) , asElement:= asElement, sRetVal:= sData); 25 | IF sData <> '' and eStatusCode = 0 THEN 26 | xTrigger := FALSE; 27 | END_IF 28 | END_IF 29 | ``` 30 | -------------------------------------------------------------------------------- /readme/set.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # SET 6 | 7 | ## Codesys usage 8 | 9 | Writes key and value: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IClient := FbRedis; 15 | xTrigger : BOOL; 16 | sKey, sValue, sData : STRING(gcMAX_STRINGLENGHT); 17 | eStatusCode : eStatusCode; 18 | typOptions : typSetOptions; 19 | END_VAR 20 | ``` 21 | 22 | ``` 23 | IF xTrigger THEN 24 | typSetOptions.uliEX := 3; // E.g. set the expire time to 3 seconds. 25 | eStatusCode := IClient.Set(psKey:= ADR(sKey), psValue:= ADR(sValue), ptypOptions:= ADR(typOptions), sRetVal:= sData); 26 | IF sData <> '' and eStatusCode = 0 THEN 27 | xTrigger := FALSE; 28 | END_IF 29 | END_IF 30 | ``` 31 | 32 | ## Note 33 | 34 | Limited to 1 pair. 35 | -------------------------------------------------------------------------------- /readme/subscriberBase.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # SUBSCRIBERBASE 6 | 7 | ## Codesys usage 8 | 9 | Subscribe channel(s) 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IClientSub : ISubscriber := FbRedis; 15 | xSubscribe : BOOL; 16 | asSubscriptions : ARRAY [1..gcMAX_SUBSCRIPTIONS] OF STRING(gcMAX_STRINGLENGHT); 17 | typSubResults : typSubResults; 18 | eStatusCode : eStatusCode; 19 | END_VAR 20 | ``` 21 | 22 | ``` 23 | eStatusCode := IClientSub.SubscriberBase(asChannel:= asSubscriptions, xAddChannel:= xSubscribe, typSubResults:= typSubResults); 24 | ``` 25 | 26 | ## Note 27 | 28 | Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional SUBSCRIBE, SSUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, SUNSUBSCRIBE, PUNSUBSCRIBE, PING, RESET and QUIT commands. However, if RESP3 is used (see HELLO) it is possible for a client to issue any commands while in subscribed state. 29 | 30 | New subscription s can only be executed if the asSubscriptions-fields are empty. To prevent writing faulty values into asSubscriptions a good practice is to use retain persistent variables for typSubResults and check these before calling method. Values will also be saved in case of reset etc. 31 | 32 | 33 | -------------------------------------------------------------------------------- /readme/tsadd.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # TSADD 6 | 7 | ## Codesys usage 8 | 9 | Appends the specified stream entry to the stream at the specified key: 10 | 11 | ``` 12 | VAR 13 | FbRedis: FbRedis; 14 | IRedis: ITimeseries := FbRedis; 15 | xConnected, xTrigger: BOOL; 16 | sKey, sValue, sResult : STRING(gcMAX_STRINGLENGHT); 17 | typTimestamp : typTimestamp; 18 | typTsOptions : typTsOptions; 19 | END_VAR 20 | ``` 21 | 22 | ``` 23 | IF xConnected THEN 24 | IF xTrigger THEN 25 | sResult := IRedis.TsAdd(psKey:= ADR(sKey), pTyptimestamp:= ADR(typTimestamp), psValue:= ADR(sValue), ptypTsOptions:= ADR(typTsOptions)); 26 | IF sResult <> '' THEN 27 | xTrigger := FALSE; 28 | END_IF 29 | END_IF 30 | END_IF 31 | ``` -------------------------------------------------------------------------------- /readme/tscreate.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # TSCREATE 6 | 7 | ## Codesys usage 8 | 9 | Create a new time series: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : ITimeseries := FbRedis; 15 | xTrigger : BOOL; 16 | sResult, sKey : STRING; 17 | typTsOptions : typSetOptions; 18 | END_VAR 19 | ``` 20 | 21 | ``` 22 | IF xConnected then 23 | IF xTrigger THEN 24 | sResult := IRedis.TsCreate(psKey:= ADR(sKey), ptypTsOptions:= ADR(typTsOptions)); 25 | IF sResult <> '' THEN 26 | xTrigger := FALSE; 27 | END_IF 28 | END_IF 29 | END_IF 30 | ``` -------------------------------------------------------------------------------- /readme/unsubscribe.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # UNSUBSCRIBE 6 | 7 | ## Codesys usage 8 | 9 | Unsubscribes to spesific channel(s). Subscriber needs to run. Feedback in atypSubResult: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : ISubscriber := FbRedis; 15 | xSubConnected, xSubscribe : BOOL; 16 | asSubscriptions, asUnsubscribe : ARRAY [1..gcMAX_SUBSCRIPTIONS] OF STRING(gcMAX_STRINGLENGHT); 17 | patypSubResult : pointer to typSubResults; 18 | END_VAR 19 | ``` 20 | 21 | ``` 22 | IF xSubConnected THEN 23 | patypSubResult := IRedis.SubscriberBase(asChannel:= asSubscriptions, xTrigger:= xSubscribe); 24 | IRedis.Unsubscribe(asChannel:= asUnsubscribe, xTrigger:= xUnsubscribe); 25 | END_IF 26 | ``` 27 | 28 | ## Note 29 | 30 | Once the client enters the subscribed state it is not supposed to issue any other commands, except for additional SUBSCRIBE, SSUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, SUNSUBSCRIBE, PUNSUBSCRIBE, PING, RESET and QUIT commands. However, if RESP3 is used (see HELLO) it is possible for a client to issue any commands while in subscribed state. -------------------------------------------------------------------------------- /readme/xadd.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # XADD 6 | 7 | ## Codesys usage 8 | 9 | Appends the specified stream entry to the stream at the specified key: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IStream := FbRedis; 15 | xTrigger: BOOL; 16 | sKey : STRING(gcMAX_STRINGLENGHT); 17 | psResult : POINTER TO STRING(gcMAX_STRINGLENGHT); 18 | asfield, asValue : ARRAY [1..gcMAX_ELEMENT] OF STRING(gcMAX_STRINGLENGHT); 19 | typEntryId : typEntryId; 20 | TypStreamOpt :TypStreamOptions; 21 | END_VAR 22 | ``` 23 | 24 | ``` 25 | psResult := IRedis.XAdd(psKey:= ADR(sKey), xAutoGenId:= xAutoGenId, typEntryId:= typEntryId, asField:= asField, asValue:= asValue, pTypStreamOpt:= ADR(TypStreamOpt), xTrigger:= xTrigger); 26 | if psResult^ <> '' then 27 | // do something 28 | END_IF 29 | ``` 30 | 31 | ## Note 32 | 33 | The typEntry is the ID if the stream specified either as 1) sEntryId or 2) uliTime_ms and uliSequence (1 and 2 can not be combined). -------------------------------------------------------------------------------- /readme/xread.md: -------------------------------------------------------------------------------- 1 | --- 2 | description: Method 3 | --- 4 | 5 | # XREAD 6 | 7 | ## Codesys usage 8 | 9 | Read data from one or multiple streams: 10 | 11 | ``` 12 | VAR 13 | FbRedis : FbRedis; 14 | IRedis : IStream := FbRedis; 15 | xXRead: BOOL; 16 | asKey : ARRAY [1..gcMAX_STREAMS] OF STRING(gcMAX_STRINGLENGHT); 17 | uiCountMax : UINT; 18 | atypEntryId : ARRAY [1..gcMAX_ELEMENT] OF typEntryId; 19 | patypStreamResult : pointer to ARRAY [1..gcMAX_STREAMS] OF typStreamResult; 20 | END_VAR 21 | ``` 22 | 23 | ``` 24 | patypStreamResult := IRedis.XRead(asKey:= asKey, uiCount:= uiCountMax, atypEntryId:= atypEntryId, xTrigger:= xXRead); 25 | ``` 26 | 27 | ## Note 28 | 29 | The typEntry is the ID if the stream specified either as 1) sEntryId or 2) uliTime_ms and uliSequence (1 and 2 can not be combined). -------------------------------------------------------------------------------- /redis-no-unixsocket.compiled-library: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorgrimjansrud/redis-codesys-lib/9a50fdf5dd13d298601fc3ba648be314b8b9e907/redis-no-unixsocket.compiled-library -------------------------------------------------------------------------------- /redis.compiled-library: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thorgrimjansrud/redis-codesys-lib/9a50fdf5dd13d298601fc3ba648be314b8b9e907/redis.compiled-library --------------------------------------------------------------------------------