FORUM CTRLX AUTOMATION
ctrlX World Partner Apps for ctrlX AUTOMATION
07-30-2024 04:20 PM
Hi,
How do I install NodeJS packages in WebIQ to use in the Code Manager?
I currently want to use it to be able to use the NodeJS fs package to access the client's file system to read the content of files, which is not possible with only JavaScript.
Thanks!
Solved! Go to Solution.
07-30-2024 07:16 PM
Hi @suitendaal ,
This is not possible as NodeJS is a server side tool and is actually a Javascript runtime in itself. The WebIQ runtime does not permit installation of NodeJS packages.
Generally, web clients prohibit access to the file system for security reasons. Imagine if you accessed a web page that started to read files off of your local PC.
If you could share a little more of what you are trying to accomplish, maybe I could help provide a solution.
07-31-2024 10:26 AM
Hi @Sgilk ,
Thank you for your answer. I already suspected this and understand the security issues.
We are using WebIQ as an HMI for a robot-integrated system. The operator can create recipes/jobs for the robot via a third party tool (Wepall), hosted in a web page. We can show this website within our WebIQ HMI and the operator can download the generated file as a .zip file to the client pc. We now want the operator to be able to upload the downloaded and unzipped files to the robot, using the WebIQ HMI. Uploading can be done using the robot's FTP server, but we need to find a way to select and unzip the downloaded files and place them in the FTP folder.
The robot, CtrlX PLC and client PC all are on the same local network. If it is not possible to access the filesystem on the client PC, perhaps it is possible to upload the .zip file to the PLC in the WebIQ HMI and run a script to unzip the files and put them in the PLC's FTP folder which then synchronizes with the robot? For example, can I make use of the
<input type="file">
HTML tag?
07-31-2024 01:23 PM - edited 07-31-2024 01:26 PM
I had a similar use case where I needed to transfer Python scripts from the local PC to the CORE itself. The UI action I defined to do this is listed below. As you suggested, I made use of the input element, type 'file'.
/**
* Custom UI-Action 'ui-upload'.
*
* Description:
* [Add description here]
*/
(function () {
var actions = shmi.pkg("visuals.session.userActions"); //get reference to userActions object
var _ipAddress = "192.168.1.1";
var _username = "";
var _password = "";
var _dir = "dir=scripts";
/**
* UI-Action 'ui-upload' implementation
*
* @params {any[]} parameters configured ui-action parameters
* ---- Initial parameters, needs to be updated manually when changed ----
* @param {string} parameters[0] ipAddress
* @param {string} parameters[1] username
* @param {string} parameters[2] password
*
*/
actions["ui-upload"] = async function (parameters) {
const im = shmi.requires("visuals.session.ItemManager"); //get reference to ItemManager instance
_ipAddress = im.readValue(parameters[0]);
_username = im.readValue(parameters[1]);
_password = im.readValue(parameters[2]);
let input = document.createElement('input');
input.type = 'file';
input.accept = '.py';
input.multiple = true;
input.onchange = async _ => {
let zip = new JSZip();
let files = Array.from(input.files);
files.forEach(f => {
zip.file(f.name, f.text());
});
await zip.generateAsync({ type: "blob" })
.then(blob => {
transfer(blob);
});
};
input.click();
};
async function transfer(blob) {
let response = await axios.post(`https://${_ipAddress}/identity-manager/api/v2/auth/token`, { name: _username, password: _password });
// Add error handling
const token = response.data.access_token;
await axios({
method: "put",
url: `https://${_ipAddress}/solutions/api/v1/solutions/DefaultSolution/configurations/appdata/archive?${_dir}`,
data: blob,
headers: { authorization: 'Bearer ' + token, "Content-Type": "application/json" },
});
// Add error handling
console.log('Transfer success...');
}
}());
I've attached a short video clip that shows its use. Note that I'm making use of the axios and jszip JavaScript libraries, which have to be packaged separately. The WebIQ documentation describes how to package such libraries is great detail.
07-31-2024 02:57 PM
Hi @bostroemc ,
Thank you, this is very helpful. I have implemented the script and it works until I want to upload the file to the plc using the solutions API. I use exactly the same url as you, but I get an axios error with status code 400: bad request.
Do I have to set something up at the PLC side? Is DefaultSolution something that I have to setup first?
Thanks!
07-31-2024 03:30 PM
In the script above, the ip address and user credentials are read from WebIQ variables. Do you have these paramaters set?
Can you confirm there is a token retrieved from the ctrlX OS authentication system?
const token = response.data.access_token;
Once you have the token, you can upload files using the webdav path. For example,
https://127.0.0.1:8443/solutions/webdav/appdata/test/test.txt
07-31-2024 03:43 PM
@suitendaal: If you have not installed the Python runtime app you may not have a scripts folder in your app data. (See the video.)
In any case, substituting the webdav path for what I used in my sample code, as @Sgilk suggests, is an excellent idea.
07-31-2024 03:50 PM
Hi @Sgilk ,
I can confirm that I get a token.
Using the webdav link I get a 401 axios error.
async function transfer(blob) {
let response = await axios.post(`https://${_ipAddress}/identity-manager/api/v2/auth/token`, { name: _username, password: _password });
// Add error handling
const token = response.data.access_token;
await axios({
method: "put",
url: `https://${_ipAddress}/solutions/webdav/appdata/test/test.txt`,
data: blob,
headers: { authorization: 'Bearer ' + token, "Content-Type": "application/json" },
});
// Add error handling
console.log('Transfer success...');
}
I am now trying to upload a .txt file and this is my transfer function.
07-31-2024 03:59 PM - edited 07-31-2024 04:00 PM
401 is an authentication error. Does the relevent user have permission to view/manage configurations?
07-31-2024 04:03 PM
The user has full access, so I guess yes?
07-31-2024 04:07 PM
Does the /test directory exist in your appdata? Try and just upload the test.txt to the appdata without the /test directory.
07-31-2024 04:19 PM
Hi @Sgilk ,
Yes, the /appdata/test directory exists, I created it using WinSCP. Also, uploading it directly to the /appdata directory gives the same 401 error.
07-31-2024 05:01 PM
I checked that my orignal script was working with ctrlX CORE firmware 2.6.x and WebIQ 2.15.9, but that the alternative webdav path suggested by sgilk (and seconded by me) was not. I am not sure why.
Note that the URL does not include the file name - the blob is a temporary compressed object consisisting of the chosen files; the CORE is un-compressing these automatically. Can you check that _dir is set correctly and re-run the original script?
.
.
.
var _dir = "dir=test";
.
.
.
async function transfer(blob) {
let response = await axios.post(`https://${_ipAddress}/identity-manager/api/v2/auth/token`, { name: _username, password: _password });
// Add error handling
const token = response.data.access_token;
await axios({
method: "put",
url: `https://${_ipAddress}/solutions/api/v1/solutions/DefaultSolution/configurations/appdata/archive?${_dir}`,
//url: `https://${_ipAddress}/solutions/webdav/appdata?${_dir}`,
data: blob,
headers: { authorization: 'Bearer ' + token, "Content-Type": "application/json" },
});
// Add error handling
console.log('Transfer success...');
}
}());
07-31-2024 05:18 PM
Hi @bostroemc ,
Using your url I get a 400 (bad request) error. I get the same error using the /solutions/{solution}/configurations/{configuration}/archive test in the API reference at https://192.168.2.10/solutions/doc/api/
Using the webdav url as @Sgilk suggested I get a 401 (unauthorized) error, even though the user has full access.
07-31-2024 05:31 PM
What version of ctrlX OS are you using?
08-01-2024 09:23 AM
08-01-2024 11:50 AM
I tried using the YARC Chrome extension by following this how-to and tried to upload some content to https://192.168.2.10/solutions/webdav/appdata/test/test.txt. Here I am prompted by Chrome to fill in a username and password. However, it doesn't accept my credentials and if I cancel I get the authorization error 401.
I tried the authorization header with capital and small letter A and I think it is clear now that something goes wrong in the authorization, but what is it?
08-01-2024 12:13 PM
I found out that Basic authentication actually does work!
Maybe something is wrong with the token generator?
I changed the transfer method and now it is working.
async function transfer(blob) {
await axios({
method: "put",
url: `https://${_ipAddress}/solutions/webdav/appdata/test/test.txt`,
data: blob,
headers: { "Content-Type": "application/json" },
auth: {
username: _username,
password: _password,
}
});
// Add error handling
console.log('Transfer success...');
}