<style> .header { text-decoration: underline; font-weight: bold; margin-top: 5px; } .bordered { padding-left: 12px; padding-top: 4px; border: 1px solid lightgrey; box-sizing: border-box; } </style> <script type="text/javascript"> function valPath15(v) { var result = true; if (this.enabled15) { var v1 = v.toLowerCase(); if (this.enabled16 && v1 == this.path16.toLowerCase()) result = false; if (result && this.enabled16j && v1 == this.path16j.toLowerCase()) result = false; } return result; } function valPath16(v) { var result = true; if (this.enabled16) { var v1 = v.toLowerCase(); if (this.enabled15 && v1 == this.path15.toLowerCase()) result = false; if (result && this.enabled16j && v1 == this.path16j.toLowerCase()) result = false; } return result; } function valPath16j(v) { var result = true; if (this.enabled16j) { var v1 = v.toLowerCase(); if (this.enabled15 && v1 == this.path15.toLowerCase()) result = false; if (result && this.enabled16 && v1 == this.path16.toLowerCase()) result = false; } return result; } RED.nodes.registerType("CS server", { category: "OCPP", color: "#3FADB5", defaults: { name: { value: "", required: false }, // port: {value: "", required: true, validate: RED.validators.number()}, port: { value: "", required: true }, portType: { value: "num", required: true }, enabled15: { value: false, required: true }, path15: { value: "", required: false, validate: valPath15 }, enabled16: { value: false, required: true }, path16: { value: "", required: false, validate: valPath16 }, enabled16j: { value: true, required: true }, path16j: { value: "", required: false, validate: valPath16j }, log: { value: false, required: true }, pathlog: { value: "", required: false }, }, inputs: 0, outputs: 2, icon: "white-globe.png", label: function () { let tmpName = "OCPP Server"; if (this.port) tmpName = "OCPP Server Port " + this.port; return this.name || tmpName; }, oneditprepare: function () { var cblist = [ { cb: "#node-input-enabled15", cont: "#container15", }, { cb: "#node-input-enabled16", cont: "#container16", }, { cb: "#node-input-enabled16j", cont: "#container16j", }, { cb: "#node-input-log", cont: "#containerlog", }, ]; function updateHideContainer(checkbox, container) { if ($(checkbox).is(":checked")) { $(container).show(); } else { $(container).hide(); } } cblist.forEach((x) => { updateHideContainer(x.cb, x.cont); $(x.cb).on("click", function () { updateHideContainer(x.cb, x.cont); }); }); $("#node-input-port").typedInput({ types: ["num","env"], typeField: "#node-input-portType" }); /* $("#node-input-port").typedInput({ types: ["num", "env"], typeField: "#node-input-portType", default: "num", }); */ }, oneditsave: function () { var e16 = $("#node-input-enabled16").is(":checked"); var e15 = $("#node-input-enabled15").is(":checked"); var e16j = $("#node-input-enabled16j").is(":checked"); if (!e16 && !e15 && !e16j) { alert("No OCPP services are enabled."); } }, }); RED.nodes.registerType("server response", { category: "OCPP", color: "#3FADB5", defaults: { name: { value: "", required: false }, }, inputs: 1, outputs: 0, align: "right", icon: "white-globe.png", label: function () { return this.name || "server response"; }, labelStyle: function () { return this.name ? "node_label_italic" : ""; }, }); RED.nodes.registerType("CP server SOAP", { category: "OCPP", color: "#3FADB5", defaults: { name: { value: "", required: false }, port: { value: "", required: true, validate: RED.validators.number() }, enabled15: { value: false, required: true }, path15: { value: "", required: true }, enabled16: { value: true, required: true }, path16: { value: "", required: true, validate: function (v) { return v.toLowerCase() != this.path15.toLowerCase(); }, }, enabled16j: { value: true, required: false }, path16j: { value: "", required: false, validate: function (v) { return v.toLowerCase() != this.path16.toLowerCase(); }, }, log: { value: true, required: true }, pathlog: { value: "", required: false }, }, inputs: 0, outputs: 1, icon: "white-globe.png", label: function () { let tmpName = "OCPP CP Server"; if (this.port) tmpName = "OCPP CP Server Port " + this.port; return this.name || tmpName; }, oneditprepare: function () { var cblist = [ { cb: "#node-input-enabled15", cont: "#container15", }, { cb: "#node-input-enabled16", cont: "#container16", }, { cb: "#node-input-enabled16j", cont: "#container16j", }, { cb: "#node-input-log", cont: "#containerlog", }, ]; function updateHideContainer(checkbox, container) { if ($(checkbox).is(":checked")) { $(container).show(); } else { $(container).hide(); } } cblist.forEach((x) => { updateHideContainer(x.cb, x.cont); $(x.cb).on("click", function () { updateHideContainer(x.cb, x.cont); }); }); }, oneditsave: function () { var e16 = $("#node-input-enabled16").is(":checked"); var e15 = $("#node-input-enabled15").is(":checked"); var e16j = $("#node-input-enabled16j").is(":checked"); if (!e16 && !e15 && !e16j) { alert("No OCPP CP services are enabled."); } }, }); RED.nodes.registerType("CS request JSON", { category: "OCPP", color: "#3FADB5", defaults: { name: { value: "", required: false }, remotecb: { value: "", type: "ocpp-remotej-cp" }, command: { value: "", required: false }, cmddata: { value: "", required: false }, log: { value: true, required: true }, pathlog: { value: "", required: false }, }, inputs: 1, outputs: 1, align: "right", icon: "white-globe.png", label: function () { var cbNode = RED.nodes.node(this.remotecb); return this.name || (cbNode ? cbNode.label() : "CS request JSON"); }, outputLabels: function () { var cbNode = RED.nodes.node(this.remotecb); return cbNode ? `from ${cbNode.label()}` : "output"; }, labelStyle: function () { return this.name ? "node_label_italic" : ""; }, }); </script> <script type="text/x-red" data-template-name="CS server"> <div class="form-row"> <label for="node-input-name"><i class="icon-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="Name (defaults to OCPP Server:<PORT>)" /> </div> <div class="form-row"> <label for="node-input-port"><i class="icon-tag"></i> Port</label> <input type="text" id="node-input-port" placeholder="Port Number (example: 8080)" /> <input type="hidden" id="node-input-portType" /> </div> <div class="header">OCPP 1.5 SOAP</div> <div class="bordered"> <div class="checkbox"> <label> <input type="checkbox" value="" id="node-input-enabled15"> 1.5 SOAP enabled </label> </div> <div id="container15" class="form-row"> <label for="node-input-path15"><i class="icon-globe"></i> Path</label> <input type="text" id="node-input-path15" placeholder="OCPP 1.5 path (example: /CentralSystemService15 )" /> </div> </div> <div class="header">OCPP 1.6 SOAP</div> <div class="bordered"> <div class="checkbox"> <label> <input type="checkbox" value="" id="node-input-enabled16"> 1.6 SOAP enabled </label> </div> <div id="container16" class="form-row"> <label for="node-input-path16" ><i class="icon-globe"></i> Path</label> <input type="text" id="node-input-path16" placeholder="OCPP 1.6 path (example: /CentralSystemService16 )" /> </div> </div> <div class="header">OCPP 1.6 JSON</div> <div class="bordered"> <div class="checkbox"> <label> <input type="checkbox" value="" id="node-input-enabled16j"> 1.6 JSON enabled </label> </div> <div id="container16j" class="form-row"> <label for="node-input-path16j" ><i class="icon-globe"></i> Path</label> <input type="text" id="node-input-path16j" placeholder="OCPP 1.6 JSON path (example: /ocpp )" /> </div> </div> <div class="header">Logging</div> <div class="bordered"> <div class="checkbox"> <label> <input type="checkbox" value="" id="node-input-log"/> logging enabled </label> </div> <div id="containerlog" class="form-row"> <label for="node-input-pathlog" > <i class="icon-globe"></i> Path </label> <input type="text" id="node-input-pathlog" placeholder="log file path and name" /> </div> </div> </script> <script type="text/x-red" data-help-name="CS server"> <p>Central System Service (CS) that accepts incomming requests from OCPP EVSEs (CP)</p> <h3>Configuration Settings</h3> <dl> <dt>Name:</dt> <dd>The name shown on the workspace</dd> <dt>Port: <i>(example) 8080</i></dt> <dd>The incoming port that the server listens on. If deploying multiple ocpp servers, the port numbers should be unique.</dd> <dt>OCPP 1.x SOAP/JSON enabled</dt> <dd>Enable/disable the protocols supported by this CS node</dd> <dt>Path: <i>(example) /CentralSystemService15</i></dt> <dd>The unique path portion of the server that needs to be configured on the ESVE</dd> <dt>logging enabled</dt> <dd>enables/disables logging for this node</dd> <dt>Path</dt> <dd>Path to file used for logging. Required if "logging enabled" is checked, otherwise logging will be disabled at runtime</dd> </dl> <h3>Outputs</h3> <dl class="messge-properties"> <dt>ocpp <span class="property-type">object</dt> <dd><code>msg.ocpp</code> objcet containing ocpp related information <ul> <li><code>command</code>: the incomming request command</li> <li><code>chargeBoxIdentity</code>: name identifying the charge box</li> <li><code>From</code>: optional address of incoming request (SOAP only)</li> <li><code>MessageID</code>: optional incoming request message id</li> </ul> </dd> <dt>payload <span class="property-type">object</dt> <dd><code>msg.payload</code> object contains the following: <ul> <li><code>command</code>: the incomming request command</li> <li><code>data</code>: arguments received with the incoming request command stored as an key/value pair</li> </ul> </dd> </dl> <h3>Details</h3> <p><code>msg.msgID</code> contains a unique message identifier that must be passed to the ocpp resonse node along with the payload (if any) of the response. It is recommended that the <code>msg</code> output from this node remain in tact and passed all the way through to the ocpp response node, only modifying or replacing the <code>msg.payload</code> portion</p> <p>The response to each incoming message has a lifespan timeout of 2 minutes, so any responses to messages must be returned within that time or the message is simply discarded</p> <p>The <code>msg.payload.data</code> arguments object received from the request vary depending on the command. Refer to the OCPP specification for information about required and optional parameters that may be received for each command. </script> <script type="text/x-red" data-template-name="server response"> <div class="form-row"> <label for="node-input-name"><i class="icon-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="Name (defaults to setup name)" /> </div> </script> <script type="text/x-red" data-help-name="server response"> <p>Return response to incoming OCPP requests</p> <h3>Configuration Settings</h3> <dl> <dt>Name:</dt> <dd>The name shown on the workspace</dd> </dl> <h3>Inputs</h3> <dl class="messge-properties"> <dt>payload <span class="property-type">object</dt> <dd><code>msg.payload</code> object containing the command specific response to the request. <blockquote><i>For example:</i><br/> <code>msg.payload</code> = { status: "Accepted" } </blockquote> </dd> </dl> <h3>Details</h3> <p><code>msg.msgID</code> contains a unique message identifier that must be passed to the ocpp resonse node along with the payload (if any) of the response. It is recommended that the <code>msg</code> output from the ocpp server node remain in tact and passed all the way through to the ocpp response node, only modifying or replacing the <code>msg.payload</code> portion</p> <p>The response to each incoming message has a lifespan timeout of 2 minutes, so any responses to messages must be returned within that time or the message is simply discarded</p> </script> <script type="text/x-red" data-template-name="CP server SOAP"> <div class="form-row"> <label for="node-input-name"><i class="icon-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="Name (defaults to :<PORT><URL>)" /> </div> <div class="form-row"> <label for="node-input-port"><i class="icon-tag"></i> Port</label> <input type="number" id="node-input-port" placeholder="Port Number (example: 8080)" /> </div> <div class="header">OCPP 1.5</div> <div class="bordered"> <div class="checkbox"> <label> <input type="checkbox" value="" id="node-input-enabled15"> 1.5 enabled </label> </div> <div id="container15" class="form-row"> <label for="node-input-path15"><i class="icon-globe"></i> Path</label> <input type="text" id="node-input-path15" placeholder="OCPP 1.5 path (example: /chargepoint15 )" /> </div> </div> <div class="header">OCPP 1.6</div> <div class="bordered"> <div class="checkbox"> <label> <input type="checkbox" value="" id="node-input-enabled16"> 1.6 enabled </label> </div> <div id="container16" class="form-row"> <label for="node-input-path16" ><i class="icon-globe"></i> Path</label> <input type="text" id="node-input-path16" placeholder="OCPP 1.6 path (example: /chargepoint16 )" /> </div> </div> <div class="header">Logging</div> <div class="bordered"> <div class="checkbox"> <label> <input type="checkbox" value="" id="node-input-log"/> logging enabled </label> </div> <div id="containerlog" class="form-row"> <label for="node-input-pathlog" > <i class="icon-globe"></i> Path </label> <input type="text" id="node-input-pathlog" placeholder="log file path and name" /> </div> </div> </script> <script type="text/x-red" data-help-name="CP server SOAP"> <p>Charge Point EVSE (CP) that accepts OCPP SOAP incomming requests from Central System Services (CS)</p> <h3>Configuration Settings</h3> <dl> <dt>Name:</dt> <dd>The name shown on the workspace</dd> <dt>Port: <i>(example) 8080</i></dt> <dd>The incoming port that the server listens on. If deploying multiple ocpp servers, the port numbers should be unique.</dd> <dt>OCPP 1.x SOAP enabled</dt> <dd>Enable/disable the protocols (OCPP 1.5/1.6 SOAP) supported by this CP node</dd> <dt>Path: <i>(example) /chargepoint15</i></dt> <dd>The unique path portion of the server that needs to be configured on the ESVE</dd> <dt>logging enabled</dt> <dd>enables/disables logging for this node</dd> <dt>Path</dt> <dd>Path to file used for logging. Required if "logging enabled" is checked, otherwise logging will be disabled at runtime</dd> </dl> <h3>Outputs</h3> <dl class="messge-properties"> <dt>ocpp <span class="property-type">object</dt> <dd><code>msg.ocpp</code> objcet containing ocpp related information <ul> <li><code>command</code>: the incomming request command</li> <li><code>chargeBoxIdentity</code>: name identifying the charge box</li> <li><code>From</code>: optional address of incoming request (SOAP only)</li> <li><code>MessageID</code>: optional incoming request message id</li> </ul> </dd> <dt>payload <span class="property-type">object</dt> <dd><code>msg.payload</code> object contains the following: <ul> <li><code>command</code>: the incomming request command</li> <li><code>data</code>: arguments received with the incoming request command stored as an key/value pair</li> </ul> </dd> </dl> <h3>Details</h3> <p><code>msg.msgID</code> contains a unique message identifier that must be passed to the ocpp resonse node along with the payload (if any) of the response. It is recommended that the <code>msg</code> output from this node remain in tact and passed all the way through to the ocpp response node, only modifying or replacing the <code>msg.payload</code> portion</p> <p>The response to each incoming message has a lifespan timeout of 2 minutes, so any responses to messages must be returned within that time or the message is simply discarded</p> <p>The <code>msg.payload.data</code> arguments object received from the request vary depending on the command. Refer to the OCPP specification for information about required and optional parameters that may be received for each command. </script> <script type="text/x-red" data-template-name="CS request JSON"> <div class="form-row"> <label for="node-input-name"><i class="icon-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="Name (defaults to EVSE setup name)" /> </div> <div class="form-row"> <label for="node-input-remotecb"><i class="icon-tag"></i> EVSE</label> <input type="text" id="node-input-remotecb" placeholder="Setup" /> </div> <div class="form-row"> <label for="node-input-command"><i class="icon-cog"></i> Command</label> <select id="node-input-command"> <option value=""><None></option> <option value="CancelReservation">Cancel Reservation</option> <option value="ChangeAvailability">Change Availability</option> <option value="ChangeConfiguration">Change Configuration</option> <option value="ClearCache">Clear Cache</option> <option value="ClearChargingProfile">*Clear Charging Profile</option> <option value="DataTransfer">Data Transfer</option> <option value="GetCompositeSchedule">*Get Composite Schedule</option> <option value="GetConfiguration">Get Configuration</option> <option value="GetDiagnostics">Get Diagnostics</option> <option value="GetLocalListVersion">Get Local List Version</option> <option value="RemoteStartTransaction">Remote Start Transaction</option> <option value="RemoteStopTransaction">Remote Stop Transaction</option> <option value="ReserveNow">Reserve Now</option> <option value="Reset">Reset</option> <option value="SendLocalList">Send Local List</option> <option value="SetChargingProfile">*Set Charging Profile</option> <option value="TriggerMessage">*Trigger Message</option> <option value="UnlockConnector">Unlock Connector</option> <option value="UpdateFirmware">Update Firmware</option> </select><br/> <p>* = 1.6 command only</p> </div> <div class="form-row"> <label for="node-input-cmddata"><i class="icon-cog"></i> Command Params</label> <textarea rows="4" cols="50" id="node-input-cmddata" placeholder="JSON formatted parameters"></textarea> </div> <!--- <div class="header">Logging</div> <div class="bordered"> <div class="checkbox"> <label> <input type="checkbox" value="" id="node-input-log"/> logging enabled </label> </div> <div id="containerlog" class="form-row"> <label for="node-input-pathlog" > <i class="icon-globe"></i> Path </label> <input type="text" id="node-input-pathlog" placeholder="log file path and name" /> </div> </div> ---> </script> <script type="text/x-red" data-help-name="CS request JSON"> <p>Send Central System (CS) OCPP JSON requests messages to EVSEs (CP)</p> <b>NOTE: This node works in conjunction with and communicates through the CS server node. A CS server node must exist on the flow in order for this node to operate correctly</b> <h3>Configuration Settings</h3> <dl> <dt>Name:</dt> <dd>The name shown on the workspace</dd> <dt>EVSE:</dt> <dd>Choose, create, or modify an ESVE (CP). NOTE: This needs to be a JSON charge point EVSE</dd> <dt>Command:</i></dt> <dd>(Optional) Select an OCPP command to send if none is passed in via <code>msg.payload.command</code></dd> <dt>Command Params:</dt> <dd>(Optional) OCPP command data object to send if none is passed in via <code>msg.payload.data</code>. Must be JSON formatted</dd> <!--- <dt>logging enabled</dt> <dd>enables/disables logging for this node</dd> <dt>Path</dt> <dd>Path to file used for logging. Required if "logging enabled" is checked, otherwise logging will be disabled at runtime</dd> ---> </dl> <h3>Inputs</h3> <dl class="message-properties"> <dt><code>msg.payload.cbId</code> <i>optional</i> <span class="property-type">string</span></dt> <dd>Charge Box Identifier or target EVSE (CP). Overrides config setting.</dd> <dt><code>msg.payload.MessageId</code> <i>optional</i> <span class="property-type">string</span></dt> <dd>A unique message identifier. Overrides default provided by the node which is unknow to the user at the time the message is sent</dd> <dt><code>msg.payload.command</code> <i>optional</i> <span class="property-type">string</span></dt> <dd>OCPP JSON "Central System" request command. Overrides config setting</dd> <dt><code>msg.payload.data</code> <i>optional</i> <span class="property-type">object</span></dt> <dd>Object containing parameters for the command. Overrides config setting</dd> </dl> <h3>Outputs</h3> <dl class="message-properties"> <dt>ocpp <span class="property-type">object</dt> <dd><code>msg.ocpp</code> objcet containing ocpp related information <ul> <li><code>command</code>: the request command sent</li> <li><code>chargeBoxIdentity</code>: name identifying the charge box</li> <li><code>MessageId</code>: The unique message identifier</li> <li><code>data</code>: object containing the parameters passed to the EVSE for the request (if any)</li> </ul> </dd> <dt>payload <span class="property-type">object</dt> <dd><code>msg.payload</code> <ul> <li><code>command</code>: The originating request command</li> <li><code>cbId</code>: The responding EVSE (CP) identifier</li> <li><code>data</code>: object containing response data sent back from the EVSE. Contents vary depending on the request command.</li> </dd> </dl> <h3>Details</h3> <p>As noted above, This node works in conjunction with and communicates through the CS server node. A CS server node must exist on the flow in order for this node to operate correctly. However, a CS server node does not reply on this node in order to work properly. This node only deals with a Central Systems requests to OCPP JSON supported EVSE's (CP). <p>Logging for this node is handled and determined by the accompnying CS server node. <p>The <code>msg.payload.data</code> arguments object received from the request vary depending on the command. Refer to the OCPP specification for information about required and optional parameters that may be received for each command. <p>You may also do local commands that control the behavior of the server. Those commands all start with prefix LOCAL_ . Currently the commands are "LOCAL_SET_ALL_AUTH_EVSES", which takes a data array of <cbId>:<password>. If password is blank then no basic authentication is required for the particular EVSE (cbId). "LOCAL_GET_ONLINE_LIST" takes no data parameters and will cause the server to return a list of EVSEs that it thinks are "online". All "LOCAL_" commands also require a "type": 99 to designate them as local (non-OCPP) commands. </script>