Publishing pluginu#

Tworzenie pluginu#

1. Utwórz katalog#

mkdir -p plugins/mynamespace--my-plugin

2. Napisz plugin.json#

{
  "id": "my-plugin",
  "name": "My Plugin",
  "version": "1.0.0",
  "description": "Opis mojego pluginu",
  "author": "twoj-nick",
  "tags": ["custom"],
  "configSchema": [
    {
      "key": "apiKey",
      "type": "string",
      "label": "API Key",
      "required": true
    }
  ],
  "exports": {
    "sensors": [
      {"id": "value", "type": "number", "description": "Current value"}
    ],
    "events": [
      {"name": "my-plugin:updated"}
    ]
  }
}

3. Napisz init.lua#

local plugin = Plugin:new("my-plugin", {
    name = "My Plugin",
    version = "1.0.0"
})

local state = { ready = false, value = 0, lastError = nil }

plugin:onInit(function(config)
    if not config.apiKey then
        plugin:log("error", "apiKey required")
        return
    end

    plugin:upsertObject("data", {ready = false, value = 0})
    plugin:sensor("value", function() return state.value end)

    local poller = plugin:poller("fetch", {
        interval = 60000,
        immediate = true,
        retry = {maxAttempts = 3, backoff = 2000},

        onTick = function(done)
            plugin:httpRequest({
                url = plugin:url("https://api.example.com/data", {
                    key = config.apiKey
                }),
                parseJson = "success"
            }, function(resp)
                if resp.err then done(resp.err); return end

                state.ready = true
                state.value = resp.json.value
                state.lastError = nil

                plugin:updateObject("data", {
                    ready = true, value = state.value,
                    updated = os.time()
                })

                local sensor = plugin:get("value")
                if sensor then sensor:notify() end

                plugin:emit("my-plugin:updated", {value = state.value},
                    {throttle = 60000})

                done()
            end)
        end,

        onError = function(err)
            state.lastError = err
            plugin:log("error", "Fetch failed: " .. err)
        end
    })
    poller:start()
end)

plugin:onCleanup(function()
    plugin:log("info", "Plugin stopped")
end)

function plugin:isReady() return state.ready end
function plugin:getValue() return state.value end
function plugin:getData() return state end
function plugin:refresh() end

return plugin

4. Napisz README.md#

# My Plugin

Opis pluginu i jak go używać.

## Konfiguracja

| Parametr | Typ | Wymagane | Opis |
|----------|-----|----------|------|
| apiKey   | string | tak | Klucz API |

## API

### Metody
- `plugin:isReady()` → boolean
- `plugin:getValue()` → number
- `plugin:getData()` → table

### Events
- `my-plugin:updated` — dane zaktualizowane

## Przykład użycia

\```lua
local p = Plugin.getPlugin("@mynamespace/my-plugin")
if p and p:isReady() then
    print(p:getValue())
end
\```

Publikacja w repozytorium#

1. Struktura repozytorium#

github.com/your-repo/vclu-plugins/
├── plugins.json
├── plugins/
│   ├── my-plugin/
│   │   ├── plugin.json
│   │   ├── init.lua
│   │   └── README.md
│   └── another-plugin/
│       ├── plugin.json
│       └── init.lua
└── README.md

2. Utwórz plugins.json#

{
  "version": 1,
  "name": "My Plugins",
  "namespace": "mynamespace",
  "description": "Moje pluginy dla vCLU",
  "author": "twoj-nick",
  "url": "https://github.com/your-repo/vclu-plugins",
  "plugins": [
    {
      "id": "my-plugin",
      "name": "My Plugin",
      "version": "1.0.0",
      "description": "Opis",
      "author": "twoj-nick",
      "path": "plugins/my-plugin",
      "tags": ["custom"]
    }
  ]
}

3. Dodaj repozytorium w vCLU#

POST /api/plugins/repositories
{
  "name": "My Plugins",
  "url": "https://github.com/your-repo/vclu-plugins"
}

Lub w UI: /pluginsAdd Repository.

Checklist przed publikacją#

  • plugin.json ma poprawne id, name, version
  • init.lua zwraca instancję pluginu (return plugin)
  • onInit() waliduje wymagane pola config
  • onCleanup() zdefiniowany (nawet pusty)
  • Public API z isReady(), getData()
  • Eventy udokumentowane w exports.events
  • README.md z opisem, konfiguracją i przykładami
  • Przetestowany lokalnie