Viability for this? Touch screen login/out project

Maybe?

const name = msg.payload

// Assuming  the msg payload contains the name of someone entering
const attendance = flow.get('attendance') || {}

let x = attendance[name]?.present
if (x == undefined)
{
    //
    node.status({text:"ONE"})
    attendance[name] = { "in": new Date(), "present": true }
    flow.set('attendance', attendance)
}
else
{
    //
    node.status({text:"TWO"})
    attendance[msg.payload] = { "out": new Date(), "present": false }
    flow.set('attendance', attendance)
}

This is given the name coming in is valid.
Rather than this "in" and "out" just the time and the "present" indicates if they were coming in or going out.

So with this as a starting block/point.

[{"id":"7259b305663811d4","type":"inject","z":"f838263ce79e696b","name":"Create attendance array","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"RESET","payloadType":"str","x":220,"y":300,"wires":[["b335992cc023d801","7d23bb2bbef09cf3"]]},{"id":"3debcbb5496f6fa6","type":"inject","z":"f838263ce79e696b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Andrew","payloadType":"str","x":180,"y":440,"wires":[["b64d03446caae4fb"]]},{"id":"dfeb03e0598f9afc","type":"inject","z":"f838263ce79e696b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Barney","payloadType":"str","x":180,"y":480,"wires":[["b64d03446caae4fb"]]},{"id":"16ec9f717ac04713","type":"inject","z":"f838263ce79e696b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Barry","payloadType":"str","x":180,"y":520,"wires":[["b64d03446caae4fb"]]},{"id":"6301dc94c94613ad","type":"inject","z":"f838263ce79e696b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Clive","payloadType":"str","x":180,"y":560,"wires":[["b64d03446caae4fb"]]},{"id":"0782f361710d99e1","type":"inject","z":"f838263ce79e696b","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Colin","payloadType":"str","x":180,"y":600,"wires":[["b64d03446caae4fb"]]},{"id":"7d23bb2bbef09cf3","type":"function","z":"f838263ce79e696b","name":"try 2","func":"const name = msg.payload\n\nif (name == \"RESET\")\n{\n    //  Really a bit more to be done here.\n    //  But for now.\n    flow.set('attendance',{});\n    node.status({text:\"NEW DAY\"})\n    return;\n}\n\n// Assuming  the msg payload contains the name of someone entering\nconst attendance = flow.get('attendance') || {}\n\nlet now = new Date().toLocaleString()\n\nlet x = attendance[name]?.present\nif (x == undefined)\n{\n    //\n    node.status({text:\"IN\"})\n    attendance[name] = { \"time\": now, \"present\": \"in\" }\n    flow.set('attendance', attendance)\n}\nelse\n{\n    //\n    node.status({text:\"OUT\"})\n    attendance[msg.payload] = { \"time\": now, \"present\": \"out\" }\n    flow.set('attendance', attendance)\n}\n","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":440,"wires":[[]]}]

No foreign nodes.

I added a RESET just to help in testing.

So, where I'm stuck.

Different node.

I need it to load the attendance from the flow and make a list of all who have NOT signed out that day.

Again, I have NO IDEA what to do or even how to.

Hints?

EDIT

New code for the function node:
Helps with keeping track of what's going on.
Maybe not too important, but ....

const name = msg.payload

if (name == "RESET")
{
    //  Really a bit more to be done here.
    //  But for now.
    flow.set('attendance',{});
    node.status({text:"NEW DAY"})
    context.set("count",0)
    context.set("ppl",0)
    return;
}

let ppl = context.get("ppl") || 0
context.set("ppl", ppl)
let count = context.get("count") || 0
let text = ""

// Assuming  the msg payload contains the name of someone entering
const attendance = flow.get('attendance') || {}

let now = new Date().toLocaleString()

let x = attendance[name]?.present
if (x == undefined)
{
    //
    //node.status({text:"IN"})
    text = "IN"
    ppl = ppl + 1
    context.set("ppl", ppl)
    count = count + 1
    context.set("count", count)
    attendance[name] = { "time": now, "present": "in" }
    flow.set('attendance', attendance)
}
else
{
    //
    //node.status({text:"OUT"})
    text = "OUT"
    ppl = ppl - 1
    context.set("ppl", ppl)
    attendance[msg.payload] = { "time": now, "present": "out" }
    flow.set('attendance', attendance)
}
node.status({text:ppl + " " + text + " " + count})

I've not read all of your posts, but wouldn't a database make life easier?
Something like mysql or mariadb.

Hi Paul.

Well, yes and no.

The thing is the REAL members list would be on another machine and I am not sure of it's structure.

But I doubt it would be directly usable in this any case.
So I would access it, strip/reformat it to what is needed here and use that.

(Probably not the best way, but the only way of which I can think at this point.)

And:

I am just playing with it to get the flow (excuse the pun) of things.

I think this would be about 2 or 3 steps down the line of things done.
And I have more to yet do. :frowning: :wink:

Could you help me with how to search the.... object (?) (array?)

{
 "Andrew":{"time":"02/07/2024, 7:11:57 pm","present":"in"},
 "Barney":{"time":"02/07/2024, 7:13:14 pm","present":"in"}
}

To find any/all which match the present as being in?
When I am doing this search it is expected the value to be out.
But I need a way to get a list of anyone who hasn't gone home.

That's where I'm kind of stuck just now.

Are you expecting people to remember to sign out?
Basic human psychology suggests it won't [always] occur to them.
After forgetting once and seeing no consequences they won't bother next time either.

If I were coding this I would definitely use a lightweight database eg SQLite on the Node-red machine.

All the insert, update, delete, request operations (there's an acronym for that but it's crud) are already available via SQL.
Data integrity is ensured, easy to sync with your master database, ...

It is a kind of requirement.
As is we have a book.

It may be EASIER if people could use a `puta to make it easier/quicker than picking up a pen, looking at what time it is and writing it down.

I have ABS(NO) idea of how to use databases.
I tried 30 years ago to try and get into databases, and failed.

The structure I'm using here/now is just to get things working.
When working, I could (maybe) change things.

But at this stage, it is all just scaffolding and frame work to get the idea of how to do it.

Why do we need to sign out?

Well, it is closing time and people leave.
The person in charge for that day has to lock up.
The look at the list and if there are people not signed out MAY have had an accident and be lying there..... die ing. (how ever it is spelt)

So a list of people showing who has NOT signed out is kind of needed.

Not quite:

{
  "Andrew Jones": {
    "entrance": "2024-07-02T15:24:03Z",
    "exit": null,
    "present": true,
  },
  ...
}

Of course, you then have to deal with name clashes - so you may need to add something extra to a name if you get a clash.

What you gave is not valid JSON because it should look like this:

[
  { "name":"Andrew","status":"" }
  { "name":"Barney","staus":"" }
]

Which could also work but is slightly more code because you now need to constantly filter the array. Since your system works by name, best to make the name the key and now you no longer have to filter anything, you can get to it immediately.

Wherever you will be processing the entry/exit, you will need the full list - OR, if you are processing in the front-end browser, you would have to constantly ask the server for updates. But that is not only inefficient but also fragile if the network is fragile.

As long as the list isn't too massive (e.g. <10k or so entries), just blast it down to the device in the morning and be done with it.

The structure I've shown IS the today list. Your master list of names will look a little different because you need different info for management reporting. Maybe something like:

{
  "Andrew Jones": {
    "lastEntrance": "2024-07-02T15:24:03Z",
    "signedUp": "2021-02-05T15:24:03Z",
    "feesDue": "2025-02-05T15:24:03Z",
    "attendance": {
      "2024-01": 3,
      "2024-02": 1,
      ...
    },
  },
  ...
}

Or whatever you want in the info - you don't need to decide immediately. The important part is the list of names.

new Date() gives you the CURRENT DATE, new_Date() would need you to write a function that returns the current date - no need for that.

Sorry, out of time for now, have to work.

1 Like

Andrew have you ever used ChatGPT or similar ?

While it may not write the whole flow for you, and you will likely need to adapt the code it does provide, it can be a helpful nudge when you get stuck on something.

As a test I just copied your exact post above, I added the first bit about Node red so that it knows what context the question is in. This is the code and a screen shot.

// Assume the input payload is the given object
let input = msg.payload;

// Initialize an empty array to store matching entries
let matchingEntries = [];

// Loop through each key in the input object
for (let key in input) {
    // Check if the "present" value is "in"
    if (input[key].present === "in") {
        // Push the matching entry (with the key) to the array
        matchingEntries.push({ name: key, ...input[key] });
    }
}

// Set the result as the payload
msg.payload = matchingEntries;

// Return the message object
return msg;

Thanks,

(in reverse order)

Yeah, I studied new date() and got it. I adjusted it to new date()..toLocaleString() just so it didn't mess we more.

Yes, the list (flow.context) is just a list of that day's activity.

The members list is about 150.

The structure - from the start.

I only used first names because I am shocking at creating names and the 5 names were for testing only to check the mechanics of it working.

When I tried the extended structure with the

[
  { "name":"Andrew","status":"" }
  { "name":"Barney","staus":"" }
]

That's done with this line - yes?
let x = attendance[name]?.present

It would only happen when people sign in/out.

Ok, going back 1 step from what I posted.
Getting the list of members.

The idea is that once a day the members list would be imported to this machine from the main machine. (Just a thought of how it would happen)

That is stored - either in a file or flow.context.
That is a layer which presents the names (first / last) when someone wants to log in.
Those buttons are created from that list.

The button is pressed and the name (first / last) is passed to this bit of code and the object is modified to indicate they have signed in today. And later them signing out.

I'll stop here as I think I've now got too many steps/phases of the code in the discussion.

Alas no, I have never used chat GPT.

It may be nice and I've looked at a couple of the pictures.

Alas it (chatGPT) is as guilty as all the sites I've visited in it doesn't explain the commands use and how they work.

So as much as the code would/could/nearly would work:
I don't really understand what it is doing. (Or is that HOW it is doing it?)

HOW do I use chatGPT?
I heard - also- that it is very VERY popular and so is somewhat difficult to get onto.

I'll look at the rest of the screen shots now - after posting.

Actually it often does as in this example:

https://chatgpt.com/c/d09e726d-c572-4e50-ab4e-6edb9b385ea8

Not any more.

Ask it a question, check the answer carefully.

Unable to load conversation d09e726d-c572-4e50-ab4e-6edb9b385ea8

Try this link:

1 Like

If you do look at the screen shots you will see it answers your comments.

Yeah, sorry Steve....

There are only 2 screen shots. I thought (incorrectly) there were more.

Looking - and not complaining - but it doesn't seem to handle the person signing out.
Or - probably - I'm not seeing it.

It is going to be painful copying the code from those that screen shot to test it.

(Sorry Julian)
The link has generic code.
Fair enough, but I am still not smart enough to know how to combine the two blocks.
The html and js.

Well, this code:

let input = msg.payload

let matchingEntries = []

for (let key in input)
{
   if (input[key].present === "in")
   {
      matchingEntries.push({name:key, ...input[key] })
   }
}

msg.payload = matchingEntries

return msg;

Sending it my example names (no last names though) all I get is [empty] in the debug on each injection of a name.

And I just now realised the code was in @smcgann99 post. Oh, gee I am not doing my self any favors.

(groan - sorry. I've sat here for .... about 5 hours today not moving. My body hurts. It is now 21:08. I think it is enough for today. Started about 09:00 today.)

If you look at the screen shot you will see your earlier post, entered into chatGPT.

The resulting code is the answer to your question, about

Take a deep breath and carefully read and digest my post :wink:

You will see in the screen shot an example of the input, I guess this would come from your "attendance" variable.

{
"Andrew": {"time": "02/07/2024, 7:11:57 pm", "present": "in"},
"Barney": {"time": "02/07/2024, 7:13:14 pm", "present": "in"},
"Charlie": {"time": "02/07/2024, 7:15:30 pm", "present": "out"}
}

and an example of what the function will output

[
{
"name": "Andrew",
"time": "02/07/2024, 7:11:57 pm",
"present": "in"
},
{
"name": "Barney",
"time": "02/07/2024, 7:13:14 pm",
"present": "in"
}
]

JavaScript is combined into a web page by using a <script> tag. That can either contain in-line JS or it can load it from a URL.

All UIBUILDER examples and templates use a standard set of 3 files: index.html, index.css and index.js. The links to the css & js files are already included in the index.html file. Though, for the default blank template, the js file is commented out since it often isn't now needed for simple use cases.

Here is a ChatGPT prompt that you might find helpful for your testing. :grinning:

Please generate me a list of 100 random people names (given-name family-name) that would be found in Australia. Return the list as a JavaScript array of strings where each entry is in the format given-name space family-name.