1
0
forked from Tank/braga
This commit is contained in:
german 2026-03-13 19:00:35 +04:00
commit f61f97a97b
119 changed files with 28113 additions and 0 deletions

93
README.md Normal file
View File

@ -0,0 +1,93 @@
https://docs.google.com/spreadsheets/d/e/2PACX-1vQrEP1eukYo2fnNs5zsQgmZTcS1PzIDYL46Lw7un1_v70jP6mgBFqpjOJno9ic-W03PrlxsC3s3YiWA/pub?gid=0&single=true&output=csv
# Поля формы добавления и редактирования емкости
- Id - скрытое поле
- Название емкости - tank_name, input
- Объем емкости (по умолчанию 38 литров) - tank_volume, ползунок от 3 до 300 литров
- Комментарии - comments, textarea
- Активная? - active, checkbox, по умолчанию включен
- ID блока датчиков, device_id, input
Блок "Исходное сырье"
- Тип сырья - raw_type, select, варианты: vine - сок винограда винных сортов, vine_wild - сок винограда диких и садовых сортов, apple_sugar - сладкий яблочный сок, apple - яблочный сок из кислых сортов яблок, pear - грушевый сок, birch - березовый сок, water - родниковая вода
- Начальный объем сока (литры) - raw_start_value, input
- Объем сока после выпаривания (литры) - raw_value, input
- Сахаристость сока начальная (%) - raw_start_sugar, input
- Сахаристость сока после выпаривания - raw_sugar, input
- Дополнительные ингридиенты - raw_addons, textarea
Блок "Брожение"
- Дата постановки на брожение - ferment_start, поле выбора даты, по умолчанию текущий день
- Дата окончания брожения - ferment_end, поле выбора даты
- Дата первого снятия с осадка - sediment_first, поле выбора даты
- Дата второго снятия с осадка - sediment_second, поле выбора даты
Блок "Шаптализация"
- Масса внесенных полисахаров (кг) - polisugar_value, input
- Дата внесения полисахаров - polisugar_date, поле выбора даты, по умолчанию текущий день
- Температура кислотного гидролиза полисахаров (градусы цельсия) - polisugar_temp, ползунок от 30 до 100
- Масса внесенной декстрозы (кг) - dextrose_value, input
- Дата внесения декстрозы - dextrose_date, поле выбора даты, по умолчанию текущий день
- Масса внесенной фруктозы (кг) - fructose_value, input
- Дата внесения фруктозы - fructose_date, поле выбора даты, по умолчанию текущий день
- Масса добавленного меда (кг) - honey_value, input
- Дата добавления меда - honey_date, поле выбора даты
- Масса внесенной кислоты (гр) - acid_value, input
- Дата внесения кислоты - acid_date, поле выбора даты
Блок "Измерения"
- Сахаристость сусла (%) - sugar_content, input
- Дата измерения сахаристости - sugar_content_date, поле выбора даты
- PH раствора - ph, input
- Дата измерения PH раствора - ph_date, поле выбора даты
- Температура сусла - temp, input
- Дата измерения температуры сусла - temp_date, поле выбора даты, по умолчанию текущий день
Кнопки:
Сохранить
Удалить
# Поля БД
tanks: id, device_id, active, tank_name, tank_volume, ferment_start, ferment_end, sediment_first, sediment_second, comments
raws: id, name, sugar
values: id, tank_id, type, value, date

BIN
database/16 Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
窒、temp、dateウ2026-03-10 18:10:23うdateウ2026-03-10 18:14:45、temp

View File

@ -0,0 +1 @@
窒、temp、dateウ2026-03-10 18:10:23うdateウ2026-03-10 18:14:45、temp

View File

@ -0,0 +1 @@
窒、temp、dateウ2026-03-10 18:10:23うdateウ2026-03-10 18:14:45、temp

142
database/array.lua Normal file
View File

@ -0,0 +1,142 @@
local _M = {}
function _M.keys(t)
local keys = {}
for key,_ in pairs(t) do
table.insert(keys, key)
end
return keys
end
function _M.count(t)
local count = 0
for key,_ in pairs(t) do
count = count + 1
end
return count
end
function _M.first(t)
for key,val in pairs(t) do
return key,val
end
end
function _M.merge(...)
local arg = {...}
if not arg[1] then return nil end
for i,v in ipairs(arg) do
for key,val in pairs(arg[i]) do
arg[1][key] = val
end
end
return arg[1]
end
function _M.sort(t)
table.sort(t)
return _M.values(t)
end
function _M.values(t)
local results = {}
for k,v in pairs(t) do
table.insert(results,v)
end
return results
end
function _M.sort_by_keys(t)
local keys = {}
local results = {}
for k,v in pairs(t) do
table.insert(keys,k)
end
table.sort(keys)
for k,v in pairs(keys) do
table.insert(results,t[k])
end
return results
end
function _M.ordnung(t)
local res = {}
for key,val in pairs(t) do
if val.order then
res[val.order] = {}
res[val.order][key] = val
else table.insert(res,t[key]) end
end
return res
end
function _M.minkey(t)
local a = {}
for n in pairs(t) do table.insert(a, n) end
table.sort(a)
return a[1]
end
function _M.in_array(t,val)
for _,v in ipairs(t) do
if v == val then return true end
end
return false
end
function _M.implode(t,before,after,sep)
local result = ''
local count = _M.count(t)
for key,val in pairs(t) do
result = result..before..val..after
if key < count then result = result..sep end
end
return result
end
function _M.binary_search(arr, target)
local left = 1
local right = #arr
while left <= right do
local mid = math.floor((left + right) / 2)
if arr[mid] == target then
return mid
elseif arr[mid] < target then
left = mid + 1
else
right = mid - 1
end
end
return nil
end
function _M.explode(t,delimiter)
local result = { }
local from = 1
local delim_from, delim_to = string.find(t, '%'..delimiter, from )
while delim_from do
table.insert( result, string.sub(t, from , delim_from-1 ) )
from = delim_to + 1
delim_from, delim_to = string.find(t, '%'..delimiter, from )
end
table.insert( result, string.sub(t, from ) )
return result
end
function _M.clear(t)
local result = {}
for key,data in pairs(t) do
if data ~= nil then table.insert(result,data) end
end
return result
end
function _M.blank(t,default)
local results = {}
for _,v in ipairs(t) do
results[''..v] = default
end
return results
end
return _M

BIN
database/cellar Normal file

Binary file not shown.

86
database/flatdb.lua Normal file
View File

@ -0,0 +1,86 @@
local mp = require("MessagePack")
local function isFile(path)
local f = io.open(path, "r")
if f then
f:close()
return true
end
return false
end
local function isDir(path)
path = string.gsub(path.."/", "//", "/")
local ok, err, code = os.rename(path, path)
if ok or code == 13 then
return true
end
return false
end
local function load_page(path)
local ret
local f = io.open(path, "rb")
if f then
ret = mp.unpack(f:read("*a"))
f:close()
end
return ret
end
local function store_page(path, page)
if type(page) == "table" then
local f = io.open(path, "wb")
if f then
f:write(mp.pack(page))
f:close()
return true
end
end
return false
end
local pool = {}
local db_funcs = {
save = function(db, p)
if p then
if type(p) == "string" and type(db[p]) == "table" then
return store_page(pool[db].."/"..p, db[p])
else
return false
end
end
for p, page in pairs(db) do
if not store_page(pool[db].."/"..p, page) then
return false
end
end
return true
end
}
local mt = {
__index = function(db, k)
if db_funcs[k] then return db_funcs[k] end
if k and pool[db] and isFile(pool[db].."/"..k) then
db[k] = load_page(pool[db].."/"..k)
end
return rawget(db, k)
end
}
pool.hack = db_funcs
return setmetatable(pool, {
__mode = "kv",
__call = function(pool, path)
assert(isDir(path), path.." is not a directory.")
if pool[path] then return pool[path] end
local db = {}
setmetatable(db, mt)
pool[path] = db
pool[db] = path
return db
end
})

BIN
database/room Normal file

Binary file not shown.

77
database/sensors.lua Normal file
View File

@ -0,0 +1,77 @@
local array = require("database.array")
local flatdb = require('database.flatdb')
local date = require('date')
local db = flatdb(ngx.var.document_root..'/database')
local _M = {}
_M.cellar = {}
_M.weather = {}
_M.room = {}
if not db.cellar then
db.cellar = {{temp=0, date = os.date('%Y-%m-%d %H:%M:%S'), warm=0, warm_status='is-danger',temp_status='is-warning'}}
db:save()
end
if not db.weather then
db.weather = {{temp=0, date = os.date('%Y-%m-%d %H:%M:%S'), warm=0, warm_status='is-success',temp_status='is-success'}}
db:save()
end
if not db.room then
db.room = {{temp=0, date = os.date('%Y-%m-%d %H:%M:%S'), warm=0, warm_status='is-danger',temp_status='is-warning'}}
db:save()
end
function _M.cellar.now()
return db.cellar[#db.cellar]
end
function _M.cellar.data(start,ends)
if not start then start = date(start) else start = date():addhours(-24) end
if not ends then ends = date(ends) else ends = date() end
local res = {}
for key,val in pairs(db.cellar) do
if date(val.date) >= start and date(val.date) <= ends then
table.insert(res,val)
end
end
return res
end
function _M.weather.now()
return db.weather[#db.weather]
end
function _M.weather.data(start,ends)
if not start then start = date(start) else start = date():addhours(-24) end
if not ends then ends = date(ends) else ends = date() end
local res = {}
for key,val in pairs(db.weather) do
if date(val.date) >= start and date(val.date) <= ends then
table.insert(res,val)
end
end
return res
end
function _M.room.now()
return db.room[#db.room]
end
function _M.room.data(start,ends)
if not start then start = date(start) else start = date():addhours(-24) end
if not ends then ends = date(ends) else ends = date() end
local res = {}
for key,val in pairs(db.room) do
if date(val.date) >= start and date(val.date) <= ends then
table.insert(res,val)
end
end
return res
end
return _M

97
database/tanks.lua Normal file
View File

@ -0,0 +1,97 @@
local array = require("database.array")
local flatdb = require('database.flatdb')
local date = require('date')
local db = flatdb(ngx.var.document_root..'/database')
local _M = {}
local fields = {
{sensor_id = 'ID сенсора'},
{name = 'Название емкости'},
{volume = 'Объем емкости'},
{date_start = 'Дата постановки на брожение'},
{raw_volume = 'Объем сока'},
{honey_weight = 'Начальная масса добавленного меда'},
{fructose_weight = 'Начальная масса добавленной фруктозы'},
{dextrose_weight = 'Начальная масса добавленной декстрозы'},
{polisugar_weight = 'Начальная масса добавленных полисахаров'},
{ph = 'PH'},
{sugar = 'Сахаристость'},
{date_end = 'Дата снятия с осадка'},
{date_restart = 'Дата постановки на повторное брожение'},
{date_reend = 'Дата повторного снятия с осадка'},
{date_blending = 'Дата купажа'},
{date_fructose_add = 'Дата добавления фруктозы'},
{add_fructose_weight = 'Масса добавляемой фруктозы'},
{date_dextrose_add = 'Дата добавления декстрозы'},
{add_dextrose_weight = 'Масса добавляемой декстрозы'},
{date_polisugar_add = 'Дата добавления полисахаров'},
{add_polisugar_weight = 'Масса добавляемых полисахаров'},
{comment = 'Комментарии'},
{archive = 'Архивная емкость'}
}
local count = 0
local results = {}
for line in io.lines(ngx.var.document_root..'/tanks.csv') do
if count>0 then
local data = array.explode(line,',')
results[count] = {notification = {typ = 'is-success', text = 'Брожение протекает нормально'}, status = 'is-primary'}
for n,value in pairs(data) do
local key,text = array.first(fields[n])
if key:find('date_') and value ~='' and pcall(date(),value) and date(value) < date() then
results[count].notification = {typ = 'is-danger', text = text}
end
results[count][key] = {value = value, text = text, order = n}
end
if not db[results[count].sensor_id.value] then
db[results[count].sensor_id.value] = {
{temp = 0, date = date():fmt('%Y-%d-%m')},
{temp = 0, date = date():fmt('%Y-%d-%m')}
}
db:save()
end
results[count].stat = db[results[count].sensor_id.value]
if (results[count]['date_blending'].value ~= '' and pcall(date(),results[count]['date_blending'].value) and date(results[count]['date_blending'].value) < date()) or (results[count]['date_end'].value ~= '' and date(results[count]['date_end'].value) < date()) then
results[count].status = 'is-success'
end
end
count = count + 1
end
function _M.all()
return results
end
function _M.active(start,ends)
if not start then start = date(start) else start = date():addhours(-24) end
if not ends then ends = date(ends) else ends = date() end
local res = {}
for key,result in pairs(results) do
if result.archive and result.archive.value ~= '' and tonumber(result.archive.value) ~= 1 then
local stat = {}
for i,val in pairs(result.stat) do
if date(val.date) >= start and date(val.date) <= ends then
table.insert(stat,val)
end
end
result.stat = stat
table.insert(res,result)
end
end
return res
end
function _M.archive()
local res = {}
for key,result in pairs(results) do
if (result.archive and result.archive.value ~= '' and tonumber(result.archive.value) == 1) or (result['date_blending'].value ~= '' and pcall(date(),result['date_blending'].value) and date(result['date_blending'].value) < date()) then
table.insert(res,result)
end
end
return res
end
return _M

BIN
database/weather Normal file

Binary file not shown.

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

213
form.html Normal file
View File

@ -0,0 +1,213 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Форма добавления емкости</title>
<!-- Bulma CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css">
<!-- JQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- JQuery UI -->
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<style>
/* Стили полей */
label {margin-bottom: 0.5rem;}
.field {margin-bottom: 1.5rem;}
.select, .control.is-expanded {width: 100%;}
button.delete {background-color: red !important; color: white !important;}
/* Ползунки */
.slider-range {margin: 1rem 0;}
</style>
</head>
<body>
<div class="section">
<form id="add-tank-form" method="post" action="/save_tank">
<input type="hidden" name="id" value="">
<!-- Основные поля -->
<div class="columns">
<div class="column is-half">
<label for="tank_name">Название емкости:</label>
<input class="input" type="text" name="tank_name" placeholder="Имя емкости">
<label for="device_id">ID блока датчиков:</label>
<input class="input" type="input" name="device_id">
<label for="tank_volume">Объем емкости (л):</label>
<div class="slider-range" data-min="3" data-max="300" data-default-value="38"></div>
<output id="volume-output" name="tank_volume">38 л</output>
<label for="comments">Комментарии:</label>
<textarea class="textarea" name="comments" rows="3" placeholder="Дополнительная информация..."></textarea>
<label for="active"><input type="checkbox" name="active" checked> Емкость активна?</label>
</div>
</div>
<!-- Исходное сырье -->
<hr />
<h3>Исходное сырье</h3>
<div class="columns">
<div class="column is-one-third">
<label for="raw_type">Тип сырья:</label>
<div class="select">
<select name="raw_type">
<option value="vine">Сок винограда винных сортов</option>
<option value="vine_wild">Сок винограда диких и садовых сортов</option>
<option value="apple_sugar">Сладкий яблочный сок</option>
<option value="apple">Яблочный сок из кислых сортов яблок</option>
<option value="pear">Грушевый сок</option>
<option value="birch">Берёзовый сок</option>
<option value="water">Родниковая вода</option>
</select>
</div>
</div>
<div class="column is-one-third">
<label for="raw_start_value">Начальный объём сока (л):</label>
<input class="input" type="number" step="any" min="0" name="raw_start_value">
<label for="raw_value">Объём сока после выпаривания (л):</label>
<input class="input" type="number" step="any" min="0" name="raw_value">
</div>
<div class="column is-one-third">
<label for="raw_start_sugar">Сахаристость сока начальная (%):</label>
<input class="input" type="number" step="any" min="0" name="raw_start_sugar">
<label for="raw_sugar">Сахаристость сока после выпаривания (%):</label>
<input class="input" type="number" step="any" min="0" name="raw_sugar">
</div>
</div>
<label for="raw_addons">Дополнительные ингредиенты:</label>
<textarea class="textarea" name="raw_addons" rows="3" placeholder="Ингредиенты..."></textarea>
<!-- Брожение -->
<hr />
<h3>Брожение</h3>
<div class="columns">
<div class="column is-one-third">
<label for="ferment_start">Дата начала брожения:</label>
<input class="input" type="date" name="ferment_start" value="<?php echo date('Y-m-d'); ?>">
</div>
<div class="column is-one-third">
<label for="ferment_end">Дата конца брожения:</label>
<input class="input" type="date" name="ferment_end">
</div>
<div class="column is-one-third">
<label for="sediment_first">Первое снятие с осадка:</label>
<input class="input" type="date" name="sediment_first">
</div>
<div class="column is-one-third">
<label for="sediment_second">Второе снятие с осадка:</label>
<input class="input" type="date" name="sediment_second">
</div>
</div>
<!-- Шаптализация -->
<hr />
<h3>Шаптализация</h3>
<div class="columns">
<div class="column is-one-third">
<label for="polisugar_value">Масса внесённых полисахаров (кг):</label>
<input class="input" type="number" step="any" min="0" name="polisugar_value">
<label for="polisugar_date">Дата внесения полисахаров:</label>
<input class="input" type="date" name="polisugar_date" value="<?php echo date('Y-m-d'); ?>">
</div>
<div class="column is-one-third">
<label for="polisugar_temp">Температура кислотного гидролиза полисахаров (°C):</label>
<div class="slider-range" data-min="30" data-max="100" data-default-value="50"></div>
<output id="temp-polysaccharide-output" name="polisugar_temp">50 °C</output>
</div>
<div class="column is-one-third">
<label for="dextrose_value">Масса внесённой декстрозы (кг):</label>
<input class="input" type="number" step="any" min="0" name="dextrose_value">
<label for="dextrose_date">Дата внесения декстрозы:</label>
<input class="input" type="date" name="dextrose_date" value="<?php echo date('Y-m-d'); ?>">
</div>
<div class="column is-one-third">
<label for="fructose_value">Масса внесённой фруктозы (кг):</label>
<input class="input" type="number" step="any" min="0" name="fructose_value">
<label for="fructose_date">Дата внесения фруктозы:</label>
<input class="input" type="date" name="fructose_date" value="<?php echo date('Y-m-d'); ?>">
</div>
<div class="column is-one-third">
<label for="honey_value">Масса добавленного мёда (кг):</label>
<input class="input" type="number" step="any" min="0" name="honey_value">
<label for="honey_date">Дата добавления мёда:</label>
<input class="input" type="date" name="honey_date">
</div>
<div class="column is-one-third">
<label for="acid_value">Масса внесённой кислоты (г):</label>
<input class="input" type="number" step="any" min="0" name="acid_value">
<label for="acid_date">Дата внесения кислоты:</label>
<input class="input" type="date" name="acid_date">
</div>
</div>
<!-- Измерения -->
<hr />
<h3>Измерения</h3>
<div class="columns">
<div class="column is-one-third">
<label for="sugar_content">Сахаристость сусла (%):</label>
<input class="input" type="number" step="any" min="0" name="sugar_content">
<label for="sugar_content_date">Дата измерения сахаристости:</label>
<input class="input" type="date" name="sugar_content_date">
</div>
<div class="column is-one-third">
<label for="ph">PH раствора:</label>
<input class="input" type="number" step="any" min="0" name="ph">
<label for="ph_date">Дата измерения pH:</label>
<input class="input" type="date" name="ph_date">
</div>
<div class="column is-one-third">
<label for="temp">Температура сусла (°C):</label>
<input class="input" type="number" step="any" min="0" name="temp">
<label for="temp_date">Дата измерения температуры:</label>
<input class="input" type="date" name="temp_date" value="<?php echo date('Y-m-d'); ?>">
</div>
</div>
<!-- Кнопки -->
<button class="button is-success" type="submit">Сохранить</button>
<button class="button delete" type="button">Удалить</button>
</form>
</div>
<script>
$(document).ready(function() {
// Создание ползунков
$('.slider-range').each(function () {
let min = $(this).data('min');
let max = $(this).data('max');
let defaultValue = $(this).data('default-value') || Math.round((min + max)/2);
let outputField = $(this).next();
$(this).slider({
range: false,
min: min,
max: max,
value: defaultValue,
slide: function(event, ui) {
outputField.val(ui.value + ' ' + (ui.value === 1 ? 'л' : 'л'));
},
change: function(event, ui) {
outputField.val(ui.value + ' ' + (ui.value === 1 ? 'л' : 'л'));
}
});
outputField.val(defaultValue + ' ' + (defaultValue === 1 ? 'л' : 'л'));
});
});
</script>
</body>
</html>

7
framework/const.lua Normal file
View File

@ -0,0 +1,7 @@
local const = {}
const['DEFAULT_SUCCESS_CODE'] = 200
const['DEFAULT_SUCCESS_MSG'] = 'Успешно'
const['DEFAULT_ERR_CODE'] = 400
return const

14
framework/handle.lua Normal file
View File

@ -0,0 +1,14 @@
local transfer = require('framework.transfer')
local resp = require('framework.resp')
local handle = function(handlers)
handler = handlers[ngx.req.get_method()]
if handler then
return resp(transfer(handler))
else
ngx.status = ngx.HTTP_NOT_ALLOWED
return
end
end
return handle

37
framework/hook.lua Normal file
View File

@ -0,0 +1,37 @@
local _M = {}
local json = require('cjson.safe')
local http = require("resty.http").new()
-- отправка запроса по https
local function req(url,body)
local res, err = http:request_uri(url, {
method = "POST",
body = body,
headers = {
["Content-Type"] = "application/x-www-form-urlencoded",
},
})
if not res then
ngx.log(ngx.INFO, "Ошибка отправки хука: ", err)
return false
end
local status = res.status
if status == 200 then
ngx.log(ngx.INFO, 'Хук отправлен: '..url..' | '..body..': '..status)
ngx.say(body)
return true
else
ngx.log(ngx.INFO, 'Ошибка отправки хука (ответ получателя не 200): '..url..' | '..body..': '..status)
return false
end
end
return _M

25
framework/resp.lua Normal file
View File

@ -0,0 +1,25 @@
local const = require('framework.const')
local json = require('cjson.safe')
local build_resp = function(data, err)
local resp = {
code = const.DEFAULT_SUCCESS_CODE,
msg = const.DEFAULT_SUCCESS_MSG
}
if err then
resp.code = err.code or const.DEFAULT_ERR_CODE
resp.msg = err.error or err
ngx.status = resp.code
elseif data then
resp.data = data
end
return resp
end
local resp = function(data, err)
return json.encode(build_resp(data, err))
end
return resp

26
framework/transfer.lua Normal file
View File

@ -0,0 +1,26 @@
local raw_transfer = function(entry)
return entry
end
local func_transfer = function(entry)
return entry()
end
local type_transfer = {}
type_transfer['string'] = raw_transfer
type_transfer['number'] = raw_transfer
type_transfer['boolean'] = raw_transfer
type_transfer['nil'] = raw_transfer
type_transfer['table'] = raw_transfer
type_transfer['function'] = func_transfer
local transfer = function(entry)
local t = type_transfer[type(entry)]
if t then
return t(entry)
else
return entry
end
end
return transfer

23
front/archive.lua Normal file
View File

@ -0,0 +1,23 @@
local template = require "resty.template"
local handle = require('framework.handle')
local tanks = require('database.tanks')
local sensors = require('database.sensors')
local function resp(start,ends)
local view = template.new("archive.html", "layout.html")
view.title = "Мои архивные чаны"
view.cellar = sensors.cellar.now()
view.room = sensors.room.now()
view.weather = sensors.weather.now()
view.tanks = tanks.archive()
view:render()
end
local request = {
GET = function()
resp()
end
}
ngx.say(handle(request))

31
front/cellar.lua Normal file
View File

@ -0,0 +1,31 @@
local template = require "resty.template"
local handle = require('framework.handle')
local sensors = require('database.sensors')
local function resp(start,ends)
local view = template.new("climate.html", "layout.html")
view.start = start
view.ends = ends
view.title = "Микроклимат подвала"
view.data = sensors.cellar.data(start,ends)
view.cellar = sensors.cellar.now()
view.room = sensors.room.now()
view.weather = sensors.weather.now()
view:render()
end
local request = {
POST = function()
ngx.req.read_body()
local args, err = ngx.req.get_post_args()
resp(string.match(args['datetimes'], "([%d-%s:]+)%s>%s([%d-%s:]+)"))
end,
GET = function()
local ends = os.date('%Y-%m-%d %H:%M:%S',os.time()+14400)
local start = os.date('%Y-%m-%d %H:%M:%S',os.time()-86400)
resp(start,ends)
end
}
ngx.say(handle(request))

32
front/index.lua Normal file
View File

@ -0,0 +1,32 @@
local template = require "resty.template"
local handle = require('framework.handle')
local tanks = require('database.tanks')
local sensors = require('database.sensors')
local function resp(start,ends)
local view = template.new("index.html", "layout.html")
view.start = start
view.ends = ends
view.title = "Мои активные чаны"
view.cellar = sensors.cellar.now()
view.room = sensors.room.now()
view.tanks = tanks.active(start,ends)
view.weather = sensors.weather.now()
view:render()
end
local request = {
POST = function()
ngx.req.read_body()
local args, err = ngx.req.get_post_args()
resp(string.match(args['datetimes'], "([%d-%s:]+)%s>%s([%d-%s:]+)"))
end,
GET = function()
local ends = os.date('%Y-%m-%d %H:%M:%S',os.time()+14400)
local start = os.date('%Y-%m-%d %H:%M:%S',os.time()-86400)
resp(start,ends)
end
}
ngx.say(handle(request))

31
front/room.lua Normal file
View File

@ -0,0 +1,31 @@
local template = require "resty.template"
local handle = require('framework.handle')
local sensors = require('database.sensors')
local function resp(start,ends)
local view = template.new("climate.html", "layout.html")
view.start = start
view.ends = ends
view.title = "Микроклимат бродильни"
view.data = sensors.room.data(start,ends)
view.cellar = sensors.cellar.now()
view.room = sensors.room.now()
view.weather = sensors.weather.now()
view:render()
end
local request = {
POST = function()
ngx.req.read_body()
local args, err = ngx.req.get_post_args()
resp(string.match(args['datetimes'], "([%d-%s:]+)%s>%s([%d-%s:]+)"))
end,
GET = function()
local ends = os.date('%Y-%m-%d %H:%M:%S',os.time()+14400)
local start = os.date('%Y-%m-%d %H:%M:%S',os.time()-86400)
resp(start,ends)
end
}
ngx.say(handle(request))

30
front/weather.lua Normal file
View File

@ -0,0 +1,30 @@
local template = require "resty.template"
local handle = require('framework.handle')
local sensors = require('database.sensors')
local function resp(start,ends)
local view = template.new("climate.html", "layout.html")
view.start = start
view.ends = ends
view.title = "Погода на улице"
view.data = sensors.weather.data(start,ends)
view.cellar = sensors.cellar.now()
view.room = sensors.room.now()
view.weather = sensors.weather.now()
view:render()
end
local request = {
POST = function()
ngx.req.read_body()
local args, err = ngx.req.get_post_args()
resp(string.match(args['datetimes'], "([%d-%s:]+)%s>%s([%d-%s:]+)"))
end,
GET = function()
local ends = os.date('%Y-%m-%d %H:%M:%S',os.time()+14400)
local start = os.date('%Y-%m-%d %H:%M:%S',os.time()-86400)
resp(start,ends)
end
}
ngx.say(handle(request))

10
getcsv.sh Normal file
View File

@ -0,0 +1,10 @@
cd /home/braga
curl -LJO \
-H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" \
-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8" \
'https://docs.google.com/spreadsheets/d/e/2PACX-1vQrEP1eukYo2fnNs5zsQgmZTcS1PzIDYL46Lw7un1_v70jP6mgBFqpjOJno9ic-W03PrlxsC3s3YiWA/pub?gid=0&single=true&output=csv'
mv braga-1.csv tanks.csv
sudo iptables -A INPUT -p tcp --dport 4888 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 4999 -j ACCEPT

59
logout.html Normal file
View File

@ -0,0 +1,59 @@
<!--
logout.html
Copyright 2026 Lida <lida@lida-laptol>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
-->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Вход в мои чаны</title>
<link rel="icon" href="public/img/icon.png" type="image/png">
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta name="generator" content="Geany 2.0" />
<style>
body {
background-color: #282a36;
overflow: hidden;
}
.background-image {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.im-getter {
max-width: 80%;
max-height: 80%;
display: block;
}
</style>
</head>
<body>
<div class="background-image" onclick="location.assign('/')">
<img src="public/img/logout_icon.png" class="im-getter"></img>
</div>
</body>
</html>

3933
logs/error.log Executable file

File diff suppressed because it is too large Load Diff

153
logs/sockets.log Executable file
View File

@ -0,0 +1,153 @@
2026/03/09 11:27:31 [info] 2460676#0: *154 client 178.176.180.141:14535 connected to 0.0.0.0:4888
2026/03/09 11:29:09 [info] 2466480#0: *2 client 178.176.180.141:28820 connected to 0.0.0.0:4999
2026/03/09 11:29:09 [error] 2466480#0: *2 lua entry thread aborted: runtime error: /home/braga/tcp.lua:39: bad argument #1 to 'log' (bad log level: -1)
stack traceback:
coroutine 0:
[C]: in function 'log'
/home/braga/tcp.lua:39: in main chunk, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:29:11 [info] 2466480#0: *12 client 178.176.180.141:1429 connected to 0.0.0.0:4999
2026/03/09 11:29:11 [error] 2466480#0: *12 lua entry thread aborted: runtime error: /home/braga/tcp.lua:39: bad argument #1 to 'log' (bad log level: -1)
stack traceback:
coroutine 0:
[C]: in function 'log'
/home/braga/tcp.lua:39: in main chunk, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:29:40 [info] 2466480#0: *21 client 178.176.180.141:13557 connected to 0.0.0.0:4999
2026/03/09 11:29:40 [error] 2466480#0: *21 lua entry thread aborted: runtime error: /home/braga/tcp.lua:39: bad argument #1 to 'log' (bad log level: -1)
stack traceback:
coroutine 0:
[C]: in function 'log'
/home/braga/tcp.lua:39: in main chunk, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:29:47 [info] 2466480#0: *26 client 178.176.180.141:21145 connected to 0.0.0.0:4888
2026/03/09 11:29:58 [info] 2466480#0: *31 client 178.176.180.141:51144 connected to 0.0.0.0:4999
2026/03/09 11:29:58 [error] 2466480#0: *31 lua entry thread aborted: runtime error: /home/braga/tcp.lua:39: bad argument #1 to 'log' (bad log level: -1)
stack traceback:
coroutine 0:
[C]: in function 'log'
/home/braga/tcp.lua:39: in main chunk, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:31:37 [info] 2466480#0: *109 client 178.176.180.141:9784 connected to 0.0.0.0:4999
2026/03/09 11:31:37 [error] 2466480#0: *109 lua entry thread aborted: runtime error: /home/braga/tcp.lua:39: bad argument #1 to 'log' (bad log level: -1)
stack traceback:
coroutine 0:
[C]: in function 'log'
/home/braga/tcp.lua:39: in main chunk, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:31:45 [info] 2466480#0: *111 client 178.176.180.141:32216 connected to 0.0.0.0:4999
2026/03/09 11:31:45 [error] 2466480#0: *111 lua entry thread aborted: runtime error: /home/braga/tcp.lua:39: bad argument #1 to 'log' (bad log level: -1)
stack traceback:
coroutine 0:
[C]: in function 'log'
/home/braga/tcp.lua:39: in main chunk, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:31:47 [info] 2466480#0: *112 client 178.176.180.141:55448 connected to 0.0.0.0:4999
2026/03/09 11:31:47 [error] 2466480#0: *112 lua entry thread aborted: runtime error: /home/braga/tcp.lua:39: bad argument #1 to 'log' (bad log level: -1)
stack traceback:
coroutine 0:
[C]: in function 'log'
/home/braga/tcp.lua:39: in main chunk, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:31:50 [info] 2466480#0: *119 client 178.176.180.141:24988 connected to 0.0.0.0:4999
2026/03/09 11:31:50 [error] 2466480#0: *119 lua entry thread aborted: runtime error: /home/braga/tcp.lua:39: bad argument #1 to 'log' (bad log level: -1)
stack traceback:
coroutine 0:
[C]: in function 'log'
/home/braga/tcp.lua:39: in main chunk, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:35:51 [info] 2466480#0: *177 client 178.176.180.141:31580 connected to 0.0.0.0:4999
2026/03/09 11:36:01 [error] 2466480#0: *177 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:36:01 [notice] 2466480#0: *177 stream [lua] tcp.lua:52: Empty data, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:37:14 [info] 2468685#0: *1 client 178.176.180.141:60737 connected to 0.0.0.0:4999
2026/03/09 11:37:18 [info] 2468685#0: *3 client 178.176.180.141:26236 connected to 0.0.0.0:4999
2026/03/09 11:38:44 [info] 2468996#0: *1 client 178.176.180.141:4954 connected to 0.0.0.0:4999
2026/03/09 11:38:44 [notice] 2468996#0: *1 stream [lua] test.lua:1: Empty data, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:38:54 [error] 2468996#0: *1 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:38:54 [notice] 2468996#0: *1 stream [lua] test.lua:5: Empty data, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:39:18 [info] 2468996#0: *18 client 178.176.180.141:60644 connected to 0.0.0.0:4999
2026/03/09 11:39:20 [info] 2468996#0: *23 client 178.176.180.141:2437 connected to 0.0.0.0:4999
2026/03/09 11:39:33 [info] 2468996#0: *24 client 178.176.180.141:26739 connected to 0.0.0.0:4999
2026/03/09 11:39:43 [error] 2468996#0: *24 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:41:50 [info] 2468996#0: *56 client 178.176.180.141:54311 connected to 0.0.0.0:4999
2026/03/09 11:42:00 [error] 2468996#0: *56 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:42:33 [info] 2468996#0: *69 client 178.176.180.141:11042 connected to 0.0.0.0:4999
2026/03/09 11:42:43 [error] 2468996#0: *69 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:43:31 [info] 2468996#0: *85 client 178.176.180.141:64901 connected to 0.0.0.0:4999
2026/03/09 11:43:41 [info] 2468996#0: *89 client 178.176.180.141:56639 connected to 0.0.0.0:4999
2026/03/09 11:43:51 [error] 2468996#0: *89 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:44:10 [info] 2468996#0: *90 client 178.176.180.141:29772 connected to 0.0.0.0:4999
2026/03/09 11:44:20 [error] 2468996#0: *90 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:44:57 [info] 2468996#0: *106 client 178.176.180.141:62296 connected to 0.0.0.0:4999
2026/03/09 11:46:37 [error] 2468996#0: *106 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:47:04 [info] 2468996#0: *197 client 178.176.180.141:5252 connected to 0.0.0.0:4999
2026/03/09 11:47:04 [error] 2468996#0: *197 failed to load external Lua file "/home/braga/test.lua": /home/braga/test.lua:6: '=' expected near '::', client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:47:06 [info] 2468996#0: *199 client 178.176.180.141:57726 connected to 0.0.0.0:4999
2026/03/09 11:47:06 [error] 2468996#0: *199 failed to load external Lua file "/home/braga/test.lua": /home/braga/test.lua:6: '=' expected near '::', client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:47:07 [info] 2468996#0: *200 client 178.176.180.141:13730 connected to 0.0.0.0:4999
2026/03/09 11:47:07 [error] 2468996#0: *200 failed to load external Lua file "/home/braga/test.lua": /home/braga/test.lua:6: '=' expected near '::', client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:47:21 [info] 2468996#0: *206 client 178.176.180.141:5369 connected to 0.0.0.0:4999
2026/03/09 11:47:21 [error] 2468996#0: *206 failed to load external Lua file "/home/braga/test.lua": /home/braga/test.lua:6: '=' expected near '::', client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:47:22 [info] 2468996#0: *207 client 178.176.180.141:9303 connected to 0.0.0.0:4999
2026/03/09 11:47:22 [error] 2468996#0: *207 failed to load external Lua file "/home/braga/test.lua": /home/braga/test.lua:6: '=' expected near '::', client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:47:25 [info] 2468996#0: *208 client 178.176.180.141:25918 connected to 0.0.0.0:4999
2026/03/09 11:47:25 [error] 2468996#0: *208 failed to load external Lua file "/home/braga/test.lua": /home/braga/test.lua:6: '=' expected near '::', client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:47:26 [info] 2468996#0: *210 client 178.176.180.141:12467 connected to 0.0.0.0:4999
2026/03/09 11:47:26 [error] 2468996#0: *210 failed to load external Lua file "/home/braga/test.lua": /home/braga/test.lua:6: '=' expected near '::', client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:47:46 [info] 2468996#0: *219 client 178.176.180.141:54232 connected to 0.0.0.0:4999
2026/03/09 11:47:48 [error] 2468996#0: *219 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:48:50 [info] 2468996#0: *293 client 178.176.180.141:53075 connected to 0.0.0.0:4999
2026/03/09 11:48:52 [error] 2468996#0: *293 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:50:14 [info] 2468996#0: *301 client 178.176.180.141:10759 connected to 0.0.0.0:4999
2026/03/09 11:50:20 [info] 2468996#0: *304 client 178.176.180.141:6910 connected to 0.0.0.0:4999
2026/03/09 11:50:54 [info] 2468996#0: *309 client 178.176.180.141:25964 connected to 0.0.0.0:4999
2026/03/09 11:50:56 [error] 2468996#0: *309 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 11:52:41 [info] 2468996#0: *335 client 178.176.180.141:9889 connected to 0.0.0.0:4999
2026/03/09 11:52:43 [error] 2468996#0: *335 stream lua tcp socket read timed out, client: 178.176.180.141, server: 0.0.0.0:4999
2026/03/09 23:29:38 [info] 2753144#0: *1091 client 85.217.140.14:43406 connected to 0.0.0.0:4888
2026/03/10 02:46:02 [info] 2841169#0: *1 client 85.217.140.51:49768 connected to 0.0.0.0:4888
2026/03/10 10:08:49 [info] 3041451#0: *17 client 64.227.97.195:33214 connected to 0.0.0.0:4888
2026/03/10 10:09:23 [info] 3041961#0: *5 client 64.227.97.195:58028 connected to 0.0.0.0:4999
2026/03/10 17:31:55 [info] 3237341#0: *1178 client 146.158.80.124:64590 connected to 0.0.0.0:4999
2026/03/10 17:31:57 [error] 3237341#0: *1178 stream lua tcp socket read timed out, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:34:20 [info] 3237339#0: *1280 client 146.158.80.124:20893 connected to 0.0.0.0:4999
2026/03/10 17:34:22 [error] 3237339#0: *1280 stream lua tcp socket read timed out, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:34:26 [info] 3237339#0: *1285 client 146.158.80.124:11563 connected to 0.0.0.0:4999
2026/03/10 17:37:21 [info] 3237339#0: *1357 client 146.158.80.124:64621 connected to 0.0.0.0:4999
2026/03/10 17:37:23 [error] 3237339#0: *1357 stream lua tcp socket read timed out, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:37:35 [info] 3237339#0: *1360 client 146.158.80.124:48760 connected to 0.0.0.0:4999
2026/03/10 17:37:43 [info] 3237339#0: *1366 client 146.158.80.124:7387 connected to 0.0.0.0:4999
2026/03/10 17:42:38 [info] 3237339#0: *1475 client 146.158.80.124:48755 connected to 0.0.0.0:4999
2026/03/10 17:42:40 [error] 3237339#0: *1475 stream lua tcp socket read timed out, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:43:59 [info] 3237339#0: *1513 client 146.158.80.124:11334 connected to 0.0.0.0:4999
2026/03/10 17:45:07 [info] 3253714#0: *7 client 146.158.80.124:27716 connected to 0.0.0.0:4999
2026/03/10 17:45:09 [info] 3253714#0: *7 stream [lua] tcp.lua:43: decode(): 2<>(ÀE 1ðåÑ'ß, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:45:09 [notice] 3253714#0: *7 stream [lua] tcp.lua:57: null, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:45:30 [info] 3253714#0: *22 client 146.158.80.124:38027 connected to 0.0.0.0:4999
2026/03/10 17:45:31 [info] 3253714#0: *22 stream [lua] tcp.lua:43: decode(): {"room":{"humi":67,"temp":12},"sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"cellar":{"humi":77,"temp":14},"weather":{"humi":57,"temp":0},"id":"test"}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:45:31 [notice] 3253714#0: *22 stream [lua] tcp.lua:57: {"cellar":{"humi":77,"temp":14},"room":{"humi":67,"temp":12},"sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"weather":{"humi":57,"temp":0},"id":"test"}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:46:37 [info] 3253714#0: *51 client 146.158.80.124:11817 connected to 0.0.0.0:4999
2026/03/10 17:46:47 [error] 3253714#0: *51 stream lua tcp socket read timed out, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:46:47 [notice] 3253714#0: *51 stream [lua] tcp.lua:52: Empty data, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:46:53 [info] 3253714#0: *59 client 146.158.80.124:16831 connected to 0.0.0.0:4999
2026/03/10 17:46:55 [info] 3253714#0: *59 stream [lua] tcp.lua:43: decode(): {"cellar":{"humi":77,"temp":14},"room":{"humi":67,"temp":12},"sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"weather":{"humi":57,"temp":0},"id":"test"}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 17:46:55 [notice] 3253714#0: *59 stream [lua] tcp.lua:57: {"sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"cellar":{"humi":77,"temp":14},"room":{"humi":67,"temp":12},"id":"test","weather":{"humi":57,"temp":0}}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:06:10 [info] 3265223#0: *1 client 146.158.80.124:1664 connected to 0.0.0.0:4999
2026/03/10 18:06:20 [error] 3265223#0: *1 stream lua tcp socket read timed out, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:06:20 [notice] 3265223#0: *1 stream [lua] tcp.lua:67: Empty data, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:06:24 [info] 3265223#0: *5 client 146.158.80.124:11833 connected to 0.0.0.0:4999
2026/03/10 18:06:25 [info] 3265223#0: *5 stream [lua] tcp.lua:58: decode(): {"cellar":{"humi":77,"temp":14},"room":{"humi":67,"temp":12},"sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"weather":{"humi":57,"temp":0},"id":"test"}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:06:25 [error] 3265223#0: *5 lua entry thread aborted: runtime error: /home/braga/tcp.lua:83: attempt to compare nil with number
stack traceback:
coroutine 0:
/home/braga/tcp.lua: in main chunk, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:06:34 [info] 3265223#0: *15 client 146.158.80.124:9568 connected to 0.0.0.0:4999
2026/03/10 18:06:36 [info] 3265223#0: *15 stream [lua] tcp.lua:58: decode(): {"cellar":{"humi":77,"temp":14},"room":{"humi":67,"temp":12},"sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"weather":{"humi":57,"temp":0},"id":"test"}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:06:36 [error] 3265223#0: *15 lua entry thread aborted: runtime error: /home/braga/tcp.lua:83: attempt to compare nil with number
stack traceback:
coroutine 0:
/home/braga/tcp.lua: in main chunk, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:10:13 [info] 3265903#0: *6 client 146.158.80.124:8958 connected to 0.0.0.0:4999
2026/03/10 18:10:20 [info] 3265903#0: *16 client 146.158.80.124:35244 connected to 0.0.0.0:4999
2026/03/10 18:10:23 [info] 3265903#0: *16 stream [lua] tcp.lua:58: decode(): {"room":{"warm":67,"temp":12},"sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"cellar":{"warm":77,"temp":14},"weather":{"warm":57,"temp":0},"id":"test"}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:10:23 [notice] 3265903#0: *16 stream [lua] tcp.lua:110: {"weather":{"date":"2026-03-10 18:10:23","warm":57,"warm_status":"is-success","temp_status":"is-success","temp":0},"cellar":{"date":"2026-03-10 18:10:23","warm":77,"warm_status":"is-success","temp_status":"is-warning","temp":14},"room":{"date":"2026-03-10 18:10:23","warm":67,"warm_status":"is-success","temp_status":"is-danger","temp":12},"id":"test","sensors":{"28:61:64:35:18:1E:74:EB":17,"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18}}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:10:23 [error] 3265903#0: *6 stream lua tcp socket read timed out, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:10:23 [notice] 3265903#0: *6 stream [lua] tcp.lua:67: Empty data, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:14:30 [info] 3266832#0: *6 client 146.158.80.124:33973 connected to 0.0.0.0:4999
2026/03/10 18:14:40 [error] 3266832#0: *6 stream lua tcp socket read timed out, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:14:40 [notice] 3266832#0: *6 stream [lua] tcp.lua:67: Empty data, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:14:44 [info] 3266835#0: *10 client 146.158.80.124:23310 connected to 0.0.0.0:4999
2026/03/10 18:14:45 [info] 3266835#0: *10 stream [lua] tcp.lua:58: decode(): {"room":{"warm":67,"temp":12},"sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"cellar":{"warm":77,"temp":14},"weather":{"warm":57,"temp":0},"id":"test"}, client: 146.158.80.124, server: 0.0.0.0:4999
2026/03/10 18:14:45 [notice] 3266835#0: *10 stream [lua] tcp.lua:113: {"room":{"warm":67,"warm_status":"is-success","temp_status":"is-danger","date":"2026-03-10 18:14:45","temp":12},"id":"test","sensors":{"28:61:64:35:18:3C:3D:61":19,"28:61:64:34:80:10:F4:39":18,"28:61:64:35:18:1E:74:EB":17},"cellar":{"warm":77,"warm_status":"is-success","temp_status":"is-warning","date":"2026-03-10 18:14:45","temp":14},"weather":{"warm":57,"warm_status":"is-success","temp_status":"is-success","date":"2026-03-10 18:14:45","temp":0}}, client: 146.158.80.124, server: 0.0.0.0:4999

117
nginx.conf Normal file
View File

@ -0,0 +1,117 @@
lua_package_path "/var/www/blog/?.lua;/var/www/braga/?.lua;/var/www/appphotos/?.lua;/var/www/apihh/?.lua;;";
lua_code_cache off;
worker_processes auto;
worker_rlimit_nofile 16000;
error_log /home/zoviet/lock/logs/nginx_error.log debug;
events {
worker_connections 1000;
}
# Работа с замками через TCP сокеты
stream {
lua_package_path "./home/zoviet/lock/?.lua;;";
lua_code_cache off;
init_by_lua '
json = require "cjson";
redis = require "resty.redis"
';
server {
listen 4999;
set $redis_host "127.0.0.1";
set $redis_port "6379";
error_log /home/zoviet/lock/logs/sockets.log debug;
content_by_lua_file /home/zoviet/lock/tcp.lua;
}
server {
listen 21;
proxy_pass 213.108.200.242:21;
}
}
# TCP сокет для обмена с замками
server {
listen 4333 ssl;
server_name hh24lock.ru;
ssl_certificate /etc/letsencrypt/live/hh24lock.ru/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hh24lock.ru/privkey.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
set $redis_host "127.0.0.1";
set $redis_port "6379";
error_log /home/zoviet/lock/logs/socket.log;
location / {
default_type 'plain/text';
content_by_lua_file /home/zoviet/lock/socket.lua;
}
}
server {
listen 80;
server_name braga;
root /var/www/braga;
error_log /var/www/braga/logs/error.log;
set $template_root /var/www/braga/templates;
location /public {
access_log off;
}
location / {
default_type text/html;
add_header 'Access-Control-Allow-Origin' '*' always;
proxy_connect_timeout 140;
proxy_read_timeout 120;
proxy_send_timeout 120;
content_by_lua_file /var/www/braga/front/index.lua;
}
location /archive {
default_type text/html;
add_header 'Access-Control-Allow-Origin' '*' always;
proxy_connect_timeout 140;
proxy_read_timeout 120;
proxy_send_timeout 120;
content_by_lua_file /var/www/braga/front/archive.lua;
}
location /room {
default_type text/html;
add_header 'Access-Control-Allow-Origin' '*' always;
proxy_connect_timeout 140;
proxy_read_timeout 120;
proxy_send_timeout 120;
content_by_lua_file /var/www/braga/front/room.lua;
}
location /cellar {
default_type text/html;
add_header 'Access-Control-Allow-Origin' '*' always;
proxy_connect_timeout 140;
proxy_read_timeout 120;
proxy_send_timeout 120;
content_by_lua_file /var/www/braga/front/cellar.lua;
}
location ~* \.(?:css(\.map)?|js(\.map)?|yaml|ico|json|pdf|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
access_log off;
}
}

View File

@ -0,0 +1 @@
<!DOCTYPE html><html lang="de"><head><meta name="description" content="Textverarbeitung, Präsentationen und Tabellen im Web"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0"><link rel="shortcut icon" href="//docs.google.com/favicon.ico"><title>Seite nicht gefunden</title><meta name="referrer" content="strict-origin-when-cross-origin"><link href="//fonts.googleapis.com/css?family=Product+Sans" rel="stylesheet" type="text/css" nonce="qKOpCCtG9YE5jr-jLswn9Q"><style nonce="qKOpCCtG9YE5jr-jLswn9Q">.goog-inline-block{position:relative;display:-moz-inline-box;display:inline-block}* html .goog-inline-block{display:inline}*:first-child+html .goog-inline-block{display:inline}#drive-logo{margin:18px 0;position:absolute;white-space:nowrap}.docs-drivelogo-img{background-image:url(//ssl.gstatic.com/images/branding/googlelogo/1x/googlelogo_color_116x41dp.png);-webkit-background-size:116px 41px;background-size:116px 41px;display:inline-block;height:41px;vertical-align:bottom;width:116px}.docs-drivelogo-text{color:#000;display:inline-block;opacity:.54;text-decoration:none;font-family:"Product Sans",Arial,Helvetica,sans-serif;font-size:32px;text-rendering:optimizeLegibility;position:relative;top:-6px;left:-7px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}@media (-webkit-min-device-pixel-ratio:1.5),(min-resolution:144dpi){.docs-drivelogo-img{background-image:url(//ssl.gstatic.com/images/branding/googlelogo/2x/googlelogo_color_116x41dp.png)}}sentinel{}</style><style type="text/css" nonce="qKOpCCtG9YE5jr-jLswn9Q">body {background-color: #fff; font-family: Arial,sans-serif; font-size: 13px; margin: 0; padding: 0;}a, a:link, a:visited {color: #112ABB;}</style><style type="text/css" nonce="qKOpCCtG9YE5jr-jLswn9Q">.errorMessage {font-size: 12pt; font-weight: bold; line-height: 150%;}</style></head><body><div id="outerContainer"><div id="innerContainer"><div style="position: absolute; top: -80px;"><div style="margin: 18px 0; position: absolute; white-space: nowrap;"><a href="//support.google.com/docs/"><img height="35px" src="//ssl.gstatic.com/docs/common/product/spreadsheets_lockup2.png" alt="Google-Logo"/></a></div></div><div align="center"><p class="errorMessage" style="padding-top: 50px">Datei kann derzeit nicht geöffnet werden.</p><p> Überprüfen Sie die Adresse und versuchen Sie es erneut.</p><div style="background: #F0F6FF; border: 1px solid black; margin-top: 35px; padding: 10px 125px; width: 300px;"><p><strong>Mit Google Drive mehr erledigen </strong></p><p>Mit den Apps in Google Drive können Sie Dokumente, Tabellen, Präsentationen und vieles mehr problemlos online erstellen, speichern und freigeben.</p><p>Weitere Informationen finden Sie hier: <a href="https://drive.google.com/start/apps">drive.google.com/start/apps</a>.</p></div></div></div></div></body><style nonce="qKOpCCtG9YE5jr-jLswn9Q">html {height: 100%; overflow: auto;}body {height: 100%; overflow: auto;}#outerContainer {margin: auto; max-width: 750px;}#innerContainer {margin-bottom: 20px; margin-left: 40px; margin-right: 40px; margin-top: 80px; position: relative;}</style></html>

74
public/css/admin.css Normal file
View File

@ -0,0 +1,74 @@
html, body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
font-size: 16px;
line-height: 1.5;
height: 100%;
}
nav.navbar {
border-top: 4px solid #276cda;
margin-bottom: 1rem;
}
.navbar-item.brand-text {
font-weight: 300;
}
.navbar-item, .navbar-link {
font-size: 14px;
font-weight: 700;
}
.columns {
width: 100%;
height: 100%;
margin-left: 0;
}
.menu-label {
letter-spacing: 1.3;
font-weight: 700;
}
.menu-list a {
font-size: 14px;
font-weight: 700;
}
.menu-list a:hover {
background-color: transparent;
}
.menu-list a.is-active {
background-color: transparent;
color: #276cda;
font-weight: 700;
}
.card {
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.18);
margin-bottom: 2rem;
}
.card-header-title {
font-weight: 400;
}
.info-tiles {
margin: 1rem 0;
}
.info-tiles .subtitle {
font-weight: 300;
}
.hero.welcome.is-info {
background: -webkit-linear-gradient(to right, #5B86E5, #36D1DC);
background: linear-gradient(to right, #5B86E5, #36D1DC);
}
.hero.welcome .title, .hero.welcome .subtitle {
}
.card .content {
font-size: 14px;
}
.card-footer-item {
font-size: 14px;
font-weight: 700;
}
.card-footer-item:hover {
}
.card-table .table {
margin-bottom: 0;
}
.events-card .card-table {
max-height: 250px;
overflow-y: scroll;
}

6928
public/css/bulma-dracula.css Normal file

File diff suppressed because it is too large Load Diff

1
public/css/bulma.min.css vendored Normal file

File diff suppressed because one or more lines are too long

4
public/css/font-awesome.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

51
public/css/login.css Normal file
View File

@ -0,0 +1,51 @@
html,body {
font-family: 'Questrial', sans-serif;
font-size: 14px;
font-weight: 300;
}
.hero.is-success {
background: #F2F6FA;
}
.hero .nav, .hero.is-success .nav {
-webkit-box-shadow: none;
box-shadow: none;
}
.box {
margin-top: 5rem;
}
.avatar {
margin-top: -70px;
padding-bottom: 20px;
}
.avatar img {
padding: 5px;
background: #fff;
border-radius: 50%;
-webkit-box-shadow: 0 2px 3px rgba(10,10,10,.1), 0 0 0 1px rgba(10,10,10,.1);
box-shadow: 0 2px 3px rgba(10,10,10,.1), 0 0 0 1px rgba(10,10,10,.1);
}
input {
font-weight: 300;
}
p {
font-weight: 700;
}
p.subtitle {
padding-top: 1rem;
}
.login-hr{
border-bottom: 1px solid black;
}
.has-text-black{
color: black;
}
.field{
padding-bottom: 10px;
}
.fa{
margin-left: 5px;
}

11904
public/css/style.css Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

545
public/fonts/demo.html Normal file
View File

@ -0,0 +1,545 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, noarchive">
<meta name="format-detection" content="telephone=no">
<title>Transfonter demo</title>
<link href="stylesheet.css" rel="stylesheet">
<style>
/*
http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* common styles */
body {
background: #f1f1f1;
color: #000;
}
.page {
background: #fff;
width: 920px;
margin: 0 auto;
padding: 20px 20px 0 20px;
overflow: hidden;
}
.font-container {
overflow-x: auto;
overflow-y: hidden;
margin-bottom: 40px;
line-height: 1.3;
white-space: nowrap;
padding-bottom: 5px;
}
h1 {
position: relative;
background: #444;
font-size: 32px;
color: #fff;
padding: 10px 20px;
margin: 0 -20px 12px -20px;
}
.letters {
font-size: 25px;
margin-bottom: 20px;
}
.s10:before {
content: '10px';
}
.s11:before {
content: '11px';
}
.s12:before {
content: '12px';
}
.s14:before {
content: '14px';
}
.s18:before {
content: '18px';
}
.s24:before {
content: '24px';
}
.s30:before {
content: '30px';
}
.s36:before {
content: '36px';
}
.s48:before {
content: '48px';
}
.s60:before {
content: '60px';
}
.s72:before {
content: '72px';
}
.s10:before, .s11:before, .s12:before, .s14:before,
.s18:before, .s24:before, .s30:before, .s36:before,
.s48:before, .s60:before, .s72:before {
font-family: Arial, sans-serif;
font-size: 10px;
font-weight: normal;
font-style: normal;
color: #999;
padding-right: 6px;
}
pre {
display: block;
position: relative;
padding: 9px;
margin: 0 0 10px;
font-family: Monaco, Menlo, Consolas, "Courier New", monospace !important;
font-size: 13px;
line-height: 1.428571429;
color: #333;
font-weight: normal !important;
font-style: normal !important;
background-color: #f5f5f5;
border: 1px solid #ccc;
overflow-x: auto;
border-radius: 4px;
}
pre:after {
display: block;
position: absolute;
right: 0;
top: 0;
content: 'Usage';
line-height: 1;
padding: 5px 8px;
font-size: 12px;
color: #767676;
background-color: #fff;
border: 1px solid #ccc;
border-right: none;
border-top: none;
border-radius: 0 4px 0 4px;
z-index: 10;
}
/* responsive */
@media (max-width: 959px) {
.page {
width: auto;
margin: 0;
}
}
</style>
</head>
<body>
<div class="page">
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 500; font-style: normal;">
<h1>VisueltPro-Medium</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 500;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: normal; font-style: normal;">
<h1>VisueltPro-Regular</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: normal;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: bold; font-style: normal;">
<h1>VisueltPro-Bold</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: bold;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 200; font-style: normal;">
<h1>VisueltPro-ExtraLight</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 200;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 100; font-style: normal;">
<h1>VisueltPro-Thin</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 100;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: normal; font-style: italic;">
<h1>VisueltPro-Italic</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: normal;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 200; font-style: italic;">
<h1>VisueltPro-ExtraLightItalic</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 200;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: bold; font-style: italic;">
<h1>VisueltPro-BoldItalic</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: bold;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 900; font-style: normal;">
<h1>VisueltPro-Black</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 900;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 500; font-style: italic;">
<h1>VisueltPro-MediumItalic</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 500;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 300; font-style: normal;">
<h1>VisueltPro-Light</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 300;
font-style: normal;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 900; font-style: italic;">
<h1>VisueltPro-BlackItalic</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 900;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 300; font-style: italic;">
<h1>VisueltPro-LightItalic</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 300;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
<div class="demo" style="font-family: 'Visuelt Pro'; font-weight: 100; font-style: italic;">
<h1>VisueltPro-ThinItalic</h1>
<pre>.your-style {
font-family: 'Visuelt Pro';
font-weight: 100;
font-style: italic;
}</pre>
<div class="font-container">
<p class="letters">
abcdefghijklmnopqrstuvwxyz<br>
ABCDEFGHIJKLMNOPQRSTUVWXYZ<br>
0123456789.:,;()*!?'@#<>$%&^+-=~
</p>
<p class="s10" style="font-size: 10px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s11" style="font-size: 11px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s12" style="font-size: 12px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s14" style="font-size: 14px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s18" style="font-size: 18px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s24" style="font-size: 24px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s30" style="font-size: 30px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s36" style="font-size: 36px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s48" style="font-size: 48px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s60" style="font-size: 60px;">The quick brown fox jumps over the lazy dog.</p>
<p class="s72" style="font-size: 72px;">The quick brown fox jumps over the lazy dog.</p>
</div>
</div>
</div>
</body>
</html>

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More