Witajcie.
Od jakiegoś czasu chciałem wyświetlać dane z kalendarza Google na aplikacji F.
Znalazłem na innym ale mniej popularnym forum człowieka o nazwie jcichon01@ który popełnił już coś takiego.
przeniosłem do siebie. A teraz krok po kroku:
1. Zakładam kalendarz Googla i dodaję testowe wydarzenie,
2. Wchodzę w ustawienia i udostępnianie tego kalendarza - znajduje "Tajny adres w formacie iCal" kopiuje,
3. Robie zmienne "GCalendar" bez wartości, druga "Month" i przypisuje dla niego "Styczeń", "Luty", ....."Grudzień" (nie pomyl się ąę musi być i duża litera),
4. Zmienna Month ustawiam na dany miesiąc (myślę, że to zautomatyzuje lada dzień),
5. Dodaje Wirtualne urządzenia Calendar_Bookings (1).vfib - (w zał.)
6. dodaje scene - która musi się odpalać tyle ile chcemy żeby aktualizować nasz kalendarz - (w zał.),
--[[
%% properties
%% globals
--]]
--[[
---------------------------------------------------------------
--------- Google Calendar synchronization ---------
--------- version 1.2 ---------
---------------------------------------------------------------
CHANGELOG:
ver 1.0
- initial
ver 1.1
- added support for events defined in .ics file as "recurring".
Few basic recurrance types are added
ver 1.2
- added handling of "all day" events; small bug fixing;
Scene used to synchronize Google Calendar with HC2. Synchronization
results are stored in the Global Variable and can be used by other
scenes or virtual devices by reading its content using for example
following:
local jsonMyGCal = fibaro:getGlobal("GCalendar");
local MyGCal = json.decode(jsonMyGCal)
for i = 1, #MyGCal do
print (MyGCal[i].Name)
print (MyGCal[i].StartDate)
print (MyGCal[i].EndDate)
print (MyGCal[i].WholeDay) - is set to "Yes" or "No"
end
Part of the code after "baran" from http://www.zwave-community.it/
-- LIST OF GLOBAL VARIABLES NEEDED ------------------------------------------
"GCalendar" holds synchronized Google Calendar events
Can be read using json.decode(fibaro:GetGlobal("GCalendar"))
and used in other scenes based on GCalendar events
"Month" Used by this script to recognize the month for sychronization.
Idea is to synchronize GCal events for this month & current year
only. This global variable is updated with Sankotronic's
"Main Scene for time based events"
--]]
--- Link to private calendar file
--- fill it with the link to you google calendar file
--- https://calendar.google.com/calendar/ical/XXXXXXXX%40gmail.com/private-googleid/yyyyy.ics
--- link can be retrieved from Google Calendar settings page
--- --> ICAL file in Calendar address - page "Calendar XXX details"
-----------------------------------------------------------------
--- VARIABLES
-----------------------------------------------------------------
local gCalUrl ="https://calendar.google.com/calendar/ical/xxxxxxxxxxxxxxx/basic.ics"
local HC = net.HTTPClient()
--- Time zone correction: 1 = gmt+1 2=gmt+2 ecc ecc
local timeZone = 1;
-- debugging variables
local responseDebug = 0; -- will show the content of GCal file after retrival
local eventDebug = 0; -- allows you to trace the parsing process
local outputDebug = 0; -- shows the event table in the structured form along with
-- global HC2 variable
local recurDebug = 0; -- extra debugging for recurring events
-- other variables
local MyGCal = {}
local currentMonth = fibaro:getGlobalValue("Month")
-- use the table to get the mapping translated into your local language
local monthMapping =
{
[ "Styczeń" ] = "January",
[ "Luty" ] = "February",
[ "Marzec" ] = "March",
[ "Kwiecień" ] = "April",
[ "Maj" ] = "May",
[ "Czerwiec" ] = "June",
[ "Lipiec" ] = "July",
[ "Sierpień" ] = "August",
[ "Wrzesień" ] = "September",
[ "Październik" ] = "October",
[ "Listopad" ] = "November",
[ "Grudzień" ] = "December"
}
local monthNumbers =
{
[ "January" ] = 1,
[ "February" ] = 2,
[ "March" ] = 3,
[ "April" ] = 4,
[ "May" ] = 5,
[ "June" ] = 6,
[ "July" ] = 7,
[ "August" ] = 8,
[ "September" ] = 9,
[ "October" ] = 10,
[ "November" ] = 11,
[ "December" ] = 12
}
local days_in_month = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-----------------------------------------------------------------
--- FUNCTIONS
-----------------------------------------------------------------
function logbug(color, message)
fibaro:debug(string.format('<%s style="color:%s;">%s</%s>', "span", color, message, "span"));
end
-- is this a whole day event?
function CheckIfWholeDay(startDate, endDate);
if tonumber(os.date("%H", startDate)) == 0 and
tonumber(os.date("%M", startDate)) == 0 and
tonumber(os.date("%S", startDate)) == 0 and
tonumber(os.date("%H", endDate)) == 0 and
tonumber(os.date("%M", endDate)) == 0 and
tonumber(os.date("%S", endDate)) == 0 then
return "Yes";
else
return "No";
end;
end;
-- append the entry to Calendar variable
function AppendToGCal(startDate, endDate, ev_name);
if tonumber(os.date("!%Y",startDate)) == tonumber(os.date("!%Y", os.time())) and
tostring(os.date("!%B",startDate)) == tostring(monthMapping[currentMonth])
then
MyGCal[#MyGCal+1] = {
Name = ev_name,
StartDate = startDate,
EndDate = endDate,
WholeDay = CheckIfWholeDay(startDate, endDate)
};
if eventDebug == 1 then
if MyGCal[i].WholeDay == "Yes" then
logbug("orange", "Wholeday event.");
end;
logbug("gray", "Record added. Event: "..ev_name..", Start: "..startDate..", End: "..endDate);
end;
else
if eventDebug == 1 then
logbug("darkgray", "Record not within selection criteria, skipping...");
end;
end;
end
--- Fetch the content of GCal - GET HTML
function gCal_GetICalData()
HC:request(
gCalUrl,
{
success = function(response)
gCalRead_2(response.data)
end,
error = httpError,
options = {method = "GET" }
}
)
end
function AppendRecuringEntry(recurance, startDate, endDate, name)
local i = 1;
local l_rule;
local l_finish;
local l_multiplier;
-- is there delimiter like "until", "count"?
l_rule = "NONE";
l_finish = "No";
for l = 1, #recurance do
-- split the lines
recurance[l] = mysplit(recurance[l], "=");
if recurance[l][1] == "COUNT" then
l_rule = "COUNT";
l_ruleEnd = recurance[l][2];
elseif recurance[l][1] == "UNTIL" then
l_rule = "UNTIL";
l_ruleEnd = gCal_UTCTimePhrase(recurance[l][2]);
end;
end;
if l_ruleEnd == nil then l_ruleEnd = "not delimited" end;
if recurDebug == 1 then
logbug("lighgray", "Recuring event: "..name..", Baseline date: "..(os.date("%x",startDate)));
if l_ruleEnd == "not delimited" then
logbug("gray", "Frequency: "..recurance[1][2]..", Rule: "..l_rule..", End by: "..l_ruleEnd);
else
logbug("gray", "Frequency: "..recurance[1][2]..", Rule: "..l_rule..", End by: "..(os.date("%x",l_ruleEnd)));
end
end;
-- recognize the dates for recurring events
while ( tonumber(os.date("%m",startDate)) <= tonumber(monthNumbers[monthMapping[currentMonth]]) -- not exceeding given month
and tonumber(os.date("!%Y",startDate)) == tonumber(os.date("!%Y", os.time())) -- and current year
and l_finish == "No" ) -- should I stop searching?
do
if recurance[1][2] == "WEEKLY" then l_multiplier = 7;
elseif recurance[1][2] == "DAILY" then l_multiplier = 1;
elseif recurance[1][2] == "MONTHLY" then l_multiplier = tonumber(days_in_month[tonumber(os.date("%m",startDate))]);
else l_multiplier = 9999; -- no handling
end;
if l_multiplier == 9999 then
l_finish = "Yes";
if recurDebug == 1 then
logbug("light red", "Unhandled rule");
end;
else
startDate = startDate + l_multiplier * (60 * 60 * 24 );
endDate = endDate + l_multiplier * (60 * 60 * 24 );
if recurDebug == 1 then
logbug("gray", "Next occurance within sycnhronization period: "..os.date("!%c",startDate));
end;
AppendToGCal(startDate, endDate, name);
-- did I reach the end?
if l_rule == "COUNT" then
if tonumber(l_ruleEnd) == i then l_finish = "Yes" end;
elseif rule == "UNTIL" then
if startDate >= l_ruleEnd then l_finish = "Yes" end;
end;
i = i + 1;
end;
end;
end
-- parse the entries
function gCalRead_2(data)
local l_StartDate
local l_EndDate
local l_Name
local l_Recurring
local l_RRule
local l_CurrentBlock
data = string.gsub(data, "\r", "") -- Remove CarageReturn
lines = mysplit(data, "\n") -- Split GCal string
for i,line in ipairs(lines) do
if responseDebug == 1 then
logbug("gray", "Line: "..i.." RESP "..line)
end
values = mysplit(line, ":")
if values[1] == "BEGIN" then
if values[2] == "VEVENT" then
l_CurrentBlock = "VEVENT"; -- we're at the beginning of event definition
l_RRule = "No"; -- no recurrance by default
end
end
if l_CurrentBlock == "VEVENT" then
--- get the GCal events START,STOP and
--- v 1.1 for recurring events - time zone included in the timestamp
--- syntax as follows: DTSTART;TZID=America/New_York:20120503T180000
--- v 1.2 in case DTSTART/DTEND contains date only -
--- it is whole/multiple day event. e.g. DTSTART;VALUE=DATE:20170312
if values[1] == "DTSTART"
or string.sub(values[1], 1, 12) == "DTSTART;TZID"
or string.sub(values[1], 1, 13) == "DTSTART;VALUE"
then
l_StartDate = gCal_UTCTimePhrase(values[2])
end
if values[1] == "DTEND"
or string.sub(values[1], 1, 10) == "DTEND;TZID"
or string.sub(values[1], 1, 11) == "DTEND;VALUE"
then
l_EndDate = gCal_UTCTimePhrase(values[2])
end
if values[1] == "SUMMARY"
then
l_Name = values[2]
end
if values[1] == "RRULE"
then
l_Recurring = mysplit(values[2], ";");
l_RRule = "Yes";
end
if values[1] == "END"
then
l_CurrentBlock = "None"
-- filter to the events of the current month (and year)
if l_RRule == "No"
then
AppendToGCal(l_StartDate, l_EndDate, l_Name);
else
AppendRecuringEntry(l_Recurring, l_StartDate, l_EndDate, l_Name);
end; -- recurance
end;
end;
end
-- Events are collected
-- pack it into global variable
gCal_OutputToGlobalVar()
end
-- parse the Google dates
function gCal_UTCTimePhrase(data)
--- v 1.2 whole-day events are defined by date only
local MyDate = {}
MyDate["Year"] = tonumber(string.sub(data, 1, 4))
MyDate["Month"] = tonumber(string.sub(data, 5, 6))
MyDate["Day"] = tonumber(string.sub(data, 7, 8))
if tonumber(string.sub(data, 10, 11)) == nil then -- whole-day event
MyDate["Hour"] = tonumber("00");
MyDate["Minute"] = tonumber("00");
MyDate["Second"] = tonumber("00");
else;
MyDate["Hour"] = tonumber(string.sub(data, 10, 11))
MyDate["Minute"] = tonumber(string.sub(data, 12, 13))
MyDate["Second"] = tonumber(string.sub(data, 14, 15))
end;
return os.time{year=MyDate["Year"], month=MyDate["Month"], day=MyDate["Day"], hour=MyDate["Hour"], min=MyDate["Minute"],sec=MyDate["Second"]}
end
function mysplit(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={} ; i=1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
i = i + 1
end
return t
end
-- Move Events into local HC2Table
function gCal_OutputToGlobalVar()
local i
CurrentTimeAndDate = os.time()
if outputDebug == 1 then
logbug("blue", "Current time: "..os.date("%c",CurrentTimeAndDate))
--sort to have it in chronological order
table.sort(MyGCal,function(a,b) return a.StartDate < b.StartDate end)
for i = 1, #MyGCal do
MyGCal[i].StartDate = MyGCal[i].StartDate + timeZone*3600;
MyGCal[i].EndDate = MyGCal[i].EndDate + timeZone*3600;
logbug("lightgreen", "Event name: "..MyGCal[i].Name);
if MyGCal[i].WholeDay == "Yes" then
logbug("gray", "Start date: "..os.date("%x",MyGCal[i].StartDate));
logbug("gray", "Finish date: "..os.date("%x",MyGCal[i].EndDate));
logbug("gray", "Wholeday event: "..MyGCal[i].WholeDay);
else
logbug("gray", "Start date: "..os.date("%c",MyGCal[i].StartDate));
logbug("gray", "Finish date: "..os.date("%c",MyGCal[i].EndDate));
end;
end;
end
logbug("gray", "Added TOTAL of: "..#MyGCal.." calendar records.")
-- move and pack into HC2 global variable
jsonMyGCal = json.encode(MyGCal);
fibaro:setGlobal("GCalendar", jsonMyGCal);
if outputDebug == 1 then
logbug("yellow", "MyGCal variable content: ");
logbug("gray", jsonMyGCal);
end
end
-----------------------------------------------------------------
--- MAIN Code
-----------------------------------------------------------------
-- update calendar
gCal_GetICalData();
logbug("green", "Synchonization completed");
7. W scenie wklejam to co skopiowałem w pkt. 2. w miejsce gdzie już jest wpis a w nim masę xxxxxxxx,
8. Odpalam scenę,
9. Odpalam urządzonko,
10. Jeśli nie ma wyników od razu to czekam parę sek. i uzupełniają się dane,
11. (W planie mam) udostępniam kalendarz żonie i razem możemy dodawać do niego pozycje.
Mam nadzieję, że komuś się to przyda.