akbooer / MetOffice_DataHub

Weather from Met Office
Apache License 2.0
1 stars 0 forks source link

openLuup.chdev:: [string "L_MetOffice_DataHub.lua"]:49: module 'openLuup.api' not found: #1

Closed nodecentral closed 1 week ago

nodecentral commented 2 weeks ago

Hi @akbooer

Just install this via the AltAppStore and recieve the following error message in the startup logs.

2024-10-30 00:08:22.468   luup.create_device:: [70] D_MetOffice_DataHub.xml / I_MetOffice_DataHub.xml / D_MetOffice_DataHub.json   (urn:akbooer-com:device:MetOffice_DataHub:1)
2024-10-30 00:08:22.468   openLuup.chdev:: [string "L_MetOffice_DataHub.lua"]:49: module 'openLuup.api' not found:
    no field package.preload['openLuup.api']
    no file './openLuup/api.lua'
    no file '/usr/local/share/lua/5.1/openLuup/api.lua'
    no file '/usr/local/share/lua/5.1/openLuup/api/init.lua'
    no file '/usr/local/lib/lua/5.1/openLuup/api.lua'
    no file '/usr/local/lib/lua/5.1/openLuup/api/init.lua'
    no file '../cmh-lu/openLuup/api.lua'
    no file 'files/openLuup/api.lua'
    no file 'openLuup/openLuup/api.lua'
    no file './openLuup/api.so'
    no file '/usr/local/lib/lua/5.1/openLuup/api.so'
    no file '/usr/local/lib/lua/5.1/loadall.so'
    no file './openLuup.so'
    no file '/usr/local/lib/lua/5.1/openLuup.so'
    no file '/usr/local/lib/lua/5.1/loadall.so'

Where can i find the required openLuup.api file ? Many thanks

akbooer commented 2 weeks ago

It’s been in the openLuup baseline since some time in 2021, IIRC.

What version are you running?

nodecentral commented 2 weeks ago

Humm, I use the @vwout docker image, and looking in openLuup, it says 2020.05.22 so I’m a little behind. By any chance is there an in place upgrade I can run ?

By any chance do the later versions fix an issue I’m having with loading my global modules at startup, i have the require statement in the startup and the log shows that it reads the file (as I have a luup.log comment in it to confirm that) but when I try to use it tells me attempt to index global 'xxpushover' (a nil value)"?

akbooer commented 2 weeks ago

I don’t use that image myself, but I do run in Docker (using a vanilla Alpine image) and do the regular upgrades.

Have you ever tried the update button?

There haven’t been any changes which affect module loading, AFAIK.

nodecentral commented 2 weeks ago

Yep, via AltUI the check for updates option, it always tells me I’m on the latest version, although I’m guessing now that does not reflect the underlying openLuup aspect.. Or is there another Update button I’m missing ?

This Module loading thing is driving me crazy, as far as I can tell it’s an exact port over from my Vera, as mentioned I have the requirestatement in the startup, and can see in the logs it reads the file (and I assume should then loaded the global functions), but when I call that function I get that error... 😢 (I responded to you on that via the smarthome forum - https://smarthome.community/topic/1614/openluup-loading-global-modules/3)

akbooer commented 2 weeks ago

It’s not AltUI which needs the update. Use the openLuup console page to select the Tables > Plugin Table page. Try the update button next to openLuup.

The require function cannot generate globals in openLuup. Modify the module to have a return statement, as per previous, and then in the require call explicitly make the return value global.

local mod = require “module”
A, B, C = mod.a, mod.b, mod.c
nodecentral commented 1 week ago

To summarise - are these all the steps to follow if you want to use your own modules in openLuup, ..

1) Create your module file. e.g. xxpushover.lua

module("xxpushover", package.seeall)

local function push_file()
    Whatever
end

local function push_basic()
    Whatever
end

local function push_ link()
    Whatever
end

2) Make sure your module file e.g. xxpushover.lua ends with a return table

return {
  push_file = push_file,
  push_basic = push_basic,
  push_link = push_link,
}

Q1:In your smarthome reply, you say to make these local, please can you explain why they cant be defined global functions and the return table is needed to make them global ?

3) In the openLuup startup add the following, so all the functions can be called..

local xxpushover = require "xxpushover"
A, B, C, D, E, F = xxpushover.push_file, xxpushover.push_basic, xxpushover.push_link

Q2: I’m a bit confused by this and how A, B, C etc. are then used ?

4) From here you should be able to run the following code ?

xxpushover.push_link("mysecretapicode", "openLuup Home Link Test", "Testing 1 2 3", 1, 'http://192.168.102.107/', "openLuup Home")

For some reason the above does not work, and I’m continuing to get the same error..

attempt to index global 'xxpushover' (a nil value)
nodecentral commented 1 week ago

Sorry for all the questions above, I had assumed I could just do a simple port over from Vera on my module files, seems it’s a lot harder/more complicated that I expected.

The alternative as you suggested on the smarthome forum, is to create the module table at the start, and define the functions directly as module components..

Keeping the pushover goal in mind, is it as simple as this, and having that in the StartUp code ?

local xxpushover = {}

function xxpushover.push_file(…)
  — whatever
end

function xxpushover.push_link(…)
  — whatever
end

return xxpushover

And then from here I should be able to run the following code in any scene, plugin i create etc.

xxpushover.push_link("mysecretapicode", "openLuup Home Link Test", "Testing 1 2 3", 1, 'http://192.168.102.107/', "openLuup Home")

I can’t deny I like the separation of having my modules as separate files (as I have a lot of them) but if this is whats best for openLuup I’ll change them all..

akbooer commented 1 week ago

Your latest comment is right on the money. I was about to write something similar but you beat me to it.

I’ll say again that the module syntax is an outmoded idiom and deprecated in the latest Lua versions… the changes you make will just be bringing modules up to date.

I’ll also say that in Vera, different plugins run in different Lua instances, which is one reason why Vera was very inefficient of memory, but it did mean that globals were confined to each plug-in. On the other hand, openLuup only runs in one Lua instance, and goes to extreme lengths (it was quite hard to implement) to keep plugins environments separate from one another (especially when some plug-in code modifies system libraries!). Ditching the module statement was a prerequisite, but a small price to pay.

akbooer commented 1 week ago

Can I close this particular issue now?

nodecentral commented 1 week ago

A couple of quick final question on this 🙏

When you create a module in this way and put it in the StartUp code.

1) where do shared local values go ? or does everything have to repeated and wrapped into a function ?

local xxpushover = {}

local http = require("socket.http")
local https = require("ssl.https")
local ltn12 = require("ltn12")
local mime = require("mime")
local lfs = require("lfs")
local url = "https://api.pushover.net/1/messages.json"

function xxpushover.push_file(…)
  — whatever
end

function xxpushover.push_link(…)
  — whatever
end

return xxpushover

2) depending on 1, as I have a number of these self contained modules to create from my previous files e.g xxsony, xxprowl, xxionos. How do I seperate them, or does eveything need to be under one module ?

nodecentral commented 1 week ago

Oh man, still no luck have tried the module as suggested in the startup, but it still gives me the same not found error. :(

attempt to index global 'xxpushover' (a nil value)

If it helps, here is my entire startup.

-- You can personalise the installation by changing these attributes,
-- which are persistent and may be removed from the Startup after a reload.

luup.log(" <<<< - Started Loading Start Up Code - >>>>> ")

local attr = luup.attr_set

-- Geographical location
attr ("City_description", "London")
attr ("Country_description", "UNITED KINGDOM")
attr ("Region_description", "England")
attr ("latitude", "50.123")
attr ("longitude", "0.3456")

-- other parameters
attr ("TemperatureFormat", "C")
attr ("PK_AccessPoint", "88800000")
attr ("currency", "£")
attr ("date_format", "dd/mm/yy")
attr ("model", "Not a Vera")
attr ("timeFormat", "24hr")

-- Any other startup processing may be inserted here...
local rblt = require("RBLuaTest")
rbLuaTest = rblt.rbLuaTest
luup.register_handler("rbLuaTest","LuaTest")

local vreport = require("xxreportlasttriphttphandler")  -- lua filename/module
lasttrip = vreport.HTTP_reports  -- call lua filename/module and required function
luup.register_handler ("lasttrip", "LastTrip")  -- register http handler

local xxpushover = {}

local http = require("socket.http")
local https = require("ssl.https")
local ltn12 = require("ltn12")
local mime = require("mime")
local lfs = require("lfs")
local url = "https://api.pushover.net/1/messages.json"
local usertoken = "myuser123token789yesitis"

http.TIMEOUT = 5
https.TIMEOUT = 5

function xxpushover.push_file (filename, apptoken, message )

    local fileHandle = io.open( filename,"rb")
    local fileContent = fileHandle:read( "*a" )
    fileHandle:close()

    local boundary = 'abcd'
    local cdfd = 'Content-Disposition: form-data; '

    local header_a = cdfd.. 'name="user"\r\n\r\n'..usertoken
    local header_b = cdfd.. 'name="token"\r\n\r\n'..apptoken
    local header_c = cdfd.. 'name="message"\r\n\r\n'..message
    local header_d = cdfd.. 'name="attachment"; filename="' ..filename.. '"\r\nContent-Type: image/jpeg'

    local MP_a = '--'..boundary..'\r\n'..header_a..'\r\n'
    local MP_b = '--'..boundary..'\r\n'..header_b..'\r\n'
    local MP_c = '--'..boundary..'\r\n'..header_c..'\r\n'
    local MP_d = '--'..boundary..'\r\n'..header_d..'\r\n\r\n'..fileContent..'\r\n'

    local MPCombined = MP_a..MP_b..MP_c..MP_d..'--'..boundary..'--\r\n'

    local   response_body = { }
    local   _, code = http.request {
            url = url ,
            method = "POST",
            headers = {    
                    --  ["Authorization"] = "Basic " .. (mime.b64(username ..":" .. password)),
                        ["Content-Length"] =  MPCombined:len(),
                        ['Content-Type'] = 'multipart/form-data; boundary=' .. boundary
                         },
            source = ltn12.source.string(MPCombined) ,
            sink = ltn12.sink.table(response_body),
                }

    luup.log(code, table.concat(response_body))
    return code, table.concat(response_body)
end

function xxpushover.push_basic(apptoken, title, message, priority)
    local status = https.request ( "https://api.pushover.net/1/messages.json" , "token="..apptoken.."&user="..usertoken.."&message="..message.."&title="..title.."&priority="..priority)
end

function xxpushover.push_link(apptoken, title, message, priority, url, urltitle)
    local status = https.request ( "https://api.pushover.net/1/messages.json" , "token="..apptoken.."&user="..usertoken.."&message="..message.."&title="..title.."&priority="..priority.."&timestamp="..os.time().."&url="..url.."&url_title="..urltitle)
end

function xxpushover.push_html(apptoken, title, message, priority)
    local status = https.request ( "https://api.pushover.net/1/messages.json" , "token="..apptoken.."&user="..usertoken.."&message="..message.."&title="..title.."&priority="..priority.."&timestamp="..os.time().."&html=1")
end

function xxpushover.push_mono(apptoken, title, message, priority)
    local status = https.request ( "https://api.pushover.net/1/messages.json" , "token="..apptoken.."&user="..usertoken.."&message="..message.."&title="..title.."&priority="..priority.."&timestamp="..os.time().."&monospace=1")
end

function xxpushover.push_specific(apptoken, title, device, message, priority, url, urltitle)
    local status = https.request ( "https://api.pushover.net/1/messages.json" , "token="..apptoken.."&user="..usertoken.."&device="..device.."&message="..message.."&title="..title.."&priority="..priority.."&timestamp="..os.time().."&url="..url.."&url_title="..urltitle)
end

return xxpushover

luup.log(" <<<< - xxpushover module loaded - >>>>> ")
akbooer commented 1 week ago

We have strayed a long way from the original topic… it’s not even about this plug-in anymore!

However, I must be explaining things very badly, because there is a basic misunderstanding here.

Your modules, which were originally separate files (yes?) should remain so, with just the small naming changes, removal of the module statement, and the addition of a return statement.

Your startup file should simply require them and assign the return to a GLOBAL variable, thus:

xxpushover = require “xxpushover”

I’m closing this issue, because it’s not relevant to DataHub.

Feel free to discuss this on the smarthome forum, or open an issue with openLuup itself.