timex_datalink_caldav 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d31450cb602c3c36c121b4ffd2240664ed8f9e550388a246f1c5e169d12f7fa
4
- data.tar.gz: 351b4213184ca2652205c80e99b7997538385bd0fab7e6ee3f4a6a57f1977247
3
+ metadata.gz: e70c9183de68e607682770a4085c86d87ba3cc0d09105c6867b445a702d8808d
4
+ data.tar.gz: 6f4248f1fc332ce55c3c7b2850a8b49ccc42d6456301235225032fb2aeb1d80e
5
5
  SHA512:
6
- metadata.gz: '08bf1aa6454647ccc74a568cb0e54e5b9724394da3f0d8ff6a8bcb0205d63ddb35208b40d99cbdbdab0be8c6b6e5c0c6febdb9db3369c415bad5cfdba7be7cb5'
7
- data.tar.gz: c2334ebf8d3d5515f4bce340808b61cacdc39ccdeaad6d2b7e7e356340fb97cf049c0316d1587d37b74dad9f4a593dcf91be66399bbfc3075018ef023a0e267d
6
+ metadata.gz: 925f98b03e5797567d02b7640febc98338c0fc9dacffa0c5771d501c266c9ee4dc59667752b489db851a1f8fe9cc4d4349fab0094ceab3f8f3de4e339731be30
7
+ data.tar.gz: 7b78a3c9ae837604bff285c6584f1dc84ae32279ce3f99ee0e32d8037f37dd3832451f07aeacca2a5e102d4a2a4016c1b5c6bc570e2aa9d31f04167975a79288
data/Gemfile CHANGED
@@ -20,3 +20,7 @@ gem "icalendar-recurrence", "~> 1.1"
20
20
  gem "activesupport", "~> 7.0"
21
21
 
22
22
  gem "tzinfo", "~> 2.0"
23
+
24
+ gem "yaml", "~> 0.2.1"
25
+
26
+ gem "open-uri", "~> 0.3.0"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- timex_datalink_caldav (0.2.0)
4
+ timex_datalink_caldav (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -21,6 +21,7 @@ GEM
21
21
  nokogiri
22
22
  concurrent-ruby (1.2.2)
23
23
  crc (0.4.2)
24
+ date (3.3.3)
24
25
  diff-lcs (1.5.0)
25
26
  domain_name (0.5.20190701)
26
27
  unf (>= 0.0.5, < 1.0.0)
@@ -51,6 +52,10 @@ GEM
51
52
  minitest (5.18.0)
52
53
  nokogiri (1.14.4-arm64-darwin)
53
54
  racc (~> 1.4)
55
+ open-uri (0.3.0)
56
+ stringio
57
+ time
58
+ uri
54
59
  public_suffix (5.0.1)
55
60
  racc (1.6.2)
56
61
  rake (13.0.6)
@@ -69,6 +74,9 @@ GEM
69
74
  rspec-support (3.12.0)
70
75
  rubyserial (0.6.0)
71
76
  ffi (~> 1.9, >= 1.9.3)
77
+ stringio (3.0.6)
78
+ time (0.2.2)
79
+ date
72
80
  timex_datalink_client (0.11.0)
73
81
  activemodel (~> 7.0.4)
74
82
  crc (~> 0.4.2)
@@ -79,6 +87,8 @@ GEM
79
87
  unf (0.1.4)
80
88
  unf_ext
81
89
  unf_ext (0.0.8.2)
90
+ uri (0.12.1)
91
+ yaml (0.2.1)
82
92
 
83
93
  PLATFORMS
84
94
  arm64-darwin-22
@@ -88,11 +98,13 @@ DEPENDENCIES
88
98
  calendav (~> 0.4.0)
89
99
  icalendar (~> 2.8)
90
100
  icalendar-recurrence (~> 1.1)
101
+ open-uri (~> 0.3.0)
91
102
  rake (~> 13.0)
92
103
  rspec (~> 3.12)
93
104
  timex_datalink_caldav!
94
105
  timex_datalink_client (~> 0.11.0)
95
106
  tzinfo (~> 2.0)
107
+ yaml (~> 0.2.1)
96
108
 
97
109
  BUNDLED WITH
98
110
  2.4.10
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Willy Hardy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # TimexDatalinkCaldav
2
2
 
3
- TimexDatalinkCaldav is a simple Ruby gem designed to sync events from a CalDAV server to a Timex Datalink watch. It can also be used as a standalone command-line interface (CLI) tool.
3
+ TimexDatalinkCaldav is a simple Ruby gem designed to sync events from a CalDAV server or an ical formatted ics file to a Timex Datalink watch. It can also be used as a standalone command-line interface (CLI) tool.
4
+
5
+ ## Pre-requisites
6
+
7
+ If you need to install Ruby, follow the Ruby installation instructions [here](https://www.ruby-lang.org/en/documentation/installation/).
4
8
 
5
9
  ## Installation
6
10
 
@@ -13,9 +17,7 @@ gem install timex_datalink_caldav
13
17
  Or add this line to your application's Gemfile:
14
18
 
15
19
  ```ruby
16
- source "https://rubygems.pkg.github.com/wjhrdy" do
17
- gem "timex_datalink_caldav"
18
- end
20
+ gem "timex_datalink_caldav"
19
21
  ```
20
22
 
21
23
  And then execute:
@@ -33,26 +35,47 @@ Here's an example of how to use the tool in your Ruby code:
33
35
  ```ruby
34
36
  require 'timex_datalink_caldav'
35
37
 
36
- client = TimexDatalinkCaldav::Client.new(your_username, your_password, your_server_uri, your_device)
37
- client.sync_to_watch
38
+ client = TimexDatalinkCaldav::Client.new(your_username, your_password, your_server_uri, your_device, your_protocol_version, days_forward)
39
+
40
+ client.parse_events
41
+ client.write_to_watch
38
42
  ```
39
43
 
40
44
  ### As a CLI Tool
41
45
 
42
- After installing the gem, you can use it as a CLI tool:
46
+ After installing the gem, you can use it as a CLI tool. You can specify the CalDAV server details directly on the command line:
43
47
 
44
48
  ```sh
45
- timex_datalink_caldav -u https://caldavendpoint.com -n your_username -p your_password -d your_device
49
+ timex_datalink_caldav -u https://caldavendpoint.com -n your_username -p your_password -d your_device -a your_protocol_version -f days_forward
46
50
  ```
47
51
 
48
- Please replace `caldavendpoint.com` `your_username`, `your_password`, and `your_device` with your actual CalDAV server, username, password, and serial device respectively.
52
+ Please replace `https://caldavendpoint.com`, `your_username`, `your_password`, `your_device`, `your_protocol_version`, and `days_forward` with your actual CalDAV server URI, username, password, serial device, protocol version, and number of days to look forward for events, respectively.
53
+
54
+ Or you can provide these details in a configuration file:
55
+
56
+ ```sh
57
+ timex_datalink_caldav -c config.yml -a 1 -d /dev/tty.usbmodem0000000000001 -f 7
58
+ ```
59
+
60
+ The configuration file should be a YAML file in the following format:
61
+
62
+ ```yaml
63
+ endpoints:
64
+ - uri: https://www.google.com/calendar/dav/email@gmail.com/events
65
+ user: email@gmail.com
66
+ password: app_password
67
+ - uri: https://caldavendpoint2.com
68
+ user: your_username2
69
+ password: your_password2
70
+ - uri: https://icalendpoint.com/example.ics
71
+ ```
49
72
 
50
- The device is a serial device that flashes an led when it receives data. On Linux, this is usually `/dev/ttyUSB0`. On macOS, this is usually `/dev/cu.usbserial-0001`. On Windows, this is usually `COM1`.
73
+ The device is a serial device that flashes an led when it receives data. On Linux, this is usually `/dev/tty*`. On macOS, this is usually `$(ls /dev/tty.usbmodem* | head -n 1)`. On Windows, this is usually `COM1`.
51
74
 
52
- If you want to use this I highly recommend pairing it with the Raspberry Pi Pico and [this project](https://github.com/famiclone6502/DIY_Datalink_Adapter). It is the cheapest and easiest way to get a serial device that works with the Timex Datalink watch.
75
+ If you want to use this, I highly recommend pairing it with the Raspberry Pi Pico and [this project](https://github.com/famiclone6502/DIY_Datalink_Adapter). It is the cheapest and easiest way to get a serial device that works with the Timex Datalink watch.
53
76
 
54
- ## Note
77
+ ## Notes
55
78
 
56
- Ensure you have the necessary dependencies installed on your system and you have the correct permissions to access the specified device.
79
+ - This gem is not affiliated with Timex, nor is it affiliated with any CalDAV server. It is simply a tool that I wrote to sync my events from my CalDAV server to my Timex Datalink watch.
57
80
 
58
- The tool currently filters down to events that have attendees and converts event times to Eastern Standard Time (EST). Events are sorted by time before syncing to the watch.
81
+ - This gem uses the anniversary feature for full day events, and the appointments feature for events with a start and end time.
@@ -0,0 +1,7 @@
1
+ # Examples
2
+
3
+ This directory contains sample configurations and code for the timex_datalink_caldav gem.
4
+
5
+ ## Configuration
6
+
7
+ `caldav.yaml.sample` is a sample configuration file for CalDAV endpoints. You should rename it to `caldav.yaml` and adjust the URI, username, and password for your endpoints.
@@ -0,0 +1,8 @@
1
+ endpoints:
2
+ - uri: https://example.com/caldav1
3
+ user: user1
4
+ password: password1
5
+ - uri: https://example.com/caldav2
6
+ user: user2
7
+ password: password2
8
+ - uri: https://example.com/example.ical
@@ -1,4 +1,5 @@
1
1
  require 'calendav'
2
+ require 'icalendar'
2
3
  require 'icalendar/recurrence'
3
4
  require 'timex_datalink_client'
4
5
  require 'active_support/time'
@@ -6,11 +7,12 @@ require 'tzinfo'
6
7
 
7
8
  module TimexDatalinkCaldav
8
9
  class Client
9
- def initialize(user, password, server_url, serial_device, protocol_version)
10
+ def initialize(user, password, server_url, serial_device, protocol_version, days_forward = 1)
10
11
  @user = user
11
12
  @password = password
12
13
  @server_url = server_url
13
14
  @serial_device = serial_device
15
+ @days_forward = days_forward
14
16
  @protocol_version = protocol_version.to_i
15
17
  @protocol_class = case @protocol_version
16
18
  when 1 then TimexDatalinkClient::Protocol1
@@ -33,49 +35,73 @@ module TimexDatalinkCaldav
33
35
  authentication: :basic_auth
34
36
  )
35
37
 
36
- # Create a new client with the credentials
37
- client = Calendav.client(credentials)
38
+ if @user && @password
39
+ # Create a new client with the credentials
40
+ client = Calendav.client(credentials)
38
41
 
39
- # Get events from the calendar for the next day
40
- client.events.list(@server_url, from: Time.now, to: Time.now + 24*60*60)
42
+ # Get events from the calendar for the next day
43
+ caldav_events = client.events.list(@server_url, from: Time.now, to: Time.now + @days_forward*24*60*60)
44
+ events = caldav_events.map { |event| Icalendar::Event.parse(event.calendar_data).first }
45
+ else
46
+ cal_file = URI.open(@server_url)
47
+ cals = Icalendar::Calendar.parse(cal_file)
48
+ cal = cals.first
49
+ events = cal.events
50
+ end
51
+
52
+ events
41
53
  end
42
54
 
43
- def sync_to_watch
55
+ def parse_events
44
56
  events = get_events
45
-
57
+
46
58
  appointments = []
59
+ anniversaries = []
47
60
  appointment_map = {} # Used to avoid duplicate appointments
48
-
61
+ anniversary_map = {} # Used to avoid duplicate anniversaries
62
+
49
63
  events.each do |event|
50
- ical_events = Icalendar::Event.parse(event.calendar_data)
51
- if ical_events.any?
52
- ical_event = ical_events.first
53
- if ical_event.attendee&.any? # Exclude events without attendees
54
- next_occurrence = ical_event.occurrences_between(Time.now, Time.now + 24*60*60).first
55
- if next_occurrence
56
- puts get_localzone
57
- est_time = next_occurrence.start_time.in_time_zone(get_localzone)
58
- key = "#{est_time}_#{ical_event.summary.to_s}"
59
- unless appointment_map[key] # Check if the event is already in the map
60
- puts "Adding appointment: #{ical_event.summary.to_s} at time #{est_time}"
61
- appointment = @protocol_class::Eeprom::Appointment.new(
62
- time: est_time,
63
- message: ical_event.summary.to_s
64
- )
65
- appointments << appointment
66
- appointment_map[key] = true
67
- end
64
+ next unless event
65
+
66
+ if event.dtstart && event.dtend && (event.dtend.to_date - event.dtstart.to_date == 1) && event.dtstart.to_datetime.hour == 0 && event.dtstart.to_datetime.min == 0 && event.dtend.to_datetime.hour == 0 && event.dtend.to_datetime.min == 0 # Checking if it is an all day event
67
+ occurrences = event.occurrences_between(Time.now, Time.now + @days_forward*24*60*60)
68
+ occurrences.each do |occurrence|
69
+ est_time = occurrence.start_time.in_time_zone(get_localzone)
70
+ key = "#{est_time}_#{event.summary.to_s}"
71
+ puts key
72
+ unless anniversary_map[key] # Check if the event is already in the map
73
+ puts "Adding anniversary: #{event.summary.to_s} at date #{event.dtstart.to_s}"
74
+ anniversary = @protocol_class::Eeprom::Anniversary.new(
75
+ time: event.dtstart.to_time,
76
+ anniversary: event.summary.to_s
77
+ )
78
+ anniversaries << anniversary
79
+ anniversary_map[key] = true
80
+ end
81
+ end
82
+ elsif event.dtstart && event.dtend
83
+ occurrences = event.occurrences_between(Time.now, Time.now + @days_forward*24*60*60)
84
+ occurrences.each do |occurrence|
85
+ est_time = occurrence.start_time.in_time_zone(get_localzone)
86
+ key = "#{est_time}_#{event.summary.to_s}"
87
+ unless appointment_map[key] # Check if the event is already in the map
88
+ puts "Adding appointment: #{event.summary.to_s} at time #{est_time}"
89
+ appointment = @protocol_class::Eeprom::Appointment.new(
90
+ time: est_time,
91
+ message: event.summary.to_s
92
+ )
93
+ appointments << appointment
94
+ appointment_map[key] = true
68
95
  end
69
96
  end
70
97
  end
71
98
  end
72
99
 
73
- # Sort the appointments by time
74
- appointments.sort_by! { |appointment| appointment.time }
75
- write_to_watch(appointments)
100
+ [appointments, anniversaries]
76
101
  end
77
102
 
78
- def write_to_watch(appointments)
103
+ def write_to_watch(appointments, anniversaries)
104
+ appointments.sort_by! { |appointment| appointment.time }
79
105
  # add 3 because it always seems to be about 3 seconds behind.
80
106
  time1 = Time.now + 3
81
107
  time2 = time1.dup.utc
@@ -128,6 +154,7 @@ module TimexDatalinkCaldav
128
154
  utc_time_name_model,
129
155
  @protocol_class::Eeprom.new(
130
156
  appointments: appointments,
157
+ anniversaries: anniversaries,
131
158
  appointment_notification_minutes: 5
132
159
  ),
133
160
  @protocol_class::End.new
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TimexDatalinkCaldav
4
- VERSION = "0.3.0"
4
+ VERSION = "1.0.0"
5
5
  end
@@ -1,5 +1,6 @@
1
- # frozen_string_literal: true
2
1
  require 'optparse'
2
+ require 'yaml'
3
+ require 'open-uri'
3
4
  require_relative "timex_datalink_caldav/client"
4
5
 
5
6
  module TimexDatalinkCaldav
@@ -9,27 +10,55 @@ module TimexDatalinkCaldav
9
10
  end
10
11
 
11
12
  def execute
12
- client = TimexDatalinkCaldav::Client.new(@options.fetch(:user), @options.fetch(:password), @options.fetch(:uri), @options.fetch(:device), @options.fetch(:api,1))
13
- client.sync_to_watch
13
+ all_appointments = []
14
+ all_anniversaries = []
15
+
16
+ @options[:endpoints].each do |endpoint|
17
+ client = TimexDatalinkCaldav::Client.new(endpoint[:user], endpoint[:password], endpoint[:uri], @options[:device], @options[:api], @options[:days_forward])
18
+ appointments, anniversaries = client.parse_events
19
+ all_appointments.concat(appointments) if appointments.any?
20
+ all_anniversaries.concat(anniversaries) if anniversaries.any?
21
+ end
22
+
23
+ if all_appointments.any? || all_anniversaries.any?
24
+ client = TimexDatalinkCaldav::Client.new(
25
+ @options[:endpoints][0][:user],
26
+ @options[:endpoints][0][:password],
27
+ @options[:endpoints][0][:uri],
28
+ @options[:device],
29
+ @options[:api],
30
+ @options[:days_forward]
31
+ )
32
+ client.write_to_watch(all_appointments, all_anniversaries)
33
+ end
14
34
  end
15
35
 
16
36
  private
17
37
 
18
38
  def parse_options(arguments)
19
- options = {}
39
+ options = { days_forward: 1 }
40
+ cli_endpoint = {}
20
41
  OptionParser.new do |opts|
21
42
  opts.banner = "Usage: timex_datalink_caldav [options]"
22
43
 
44
+ opts.on("-c", "--config FILE", "Configuration file") do |v|
45
+ raise ArgumentError, "Both CLI options and configuration file provided. Please provide only one." if cli_endpoint.any?
46
+ parsed_config = YAML.load_file(v)
47
+ options[:endpoints] = parsed_config['endpoints'].map do |endpoint|
48
+ endpoint.each_with_object({}) { |(k, v), result| result[k.to_sym] = v }
49
+ end
50
+ end
51
+
23
52
  opts.on("-u", "--uri URI", "CalDAV server URI") do |v|
24
- options[:uri] = v
53
+ cli_endpoint[:uri] = v
25
54
  end
26
55
 
27
56
  opts.on("-n", "--user USERNAME", "Username for CalDAV server") do |v|
28
- options[:user] = v
57
+ cli_endpoint[:user] = v
29
58
  end
30
59
 
31
60
  opts.on("-p", "--password PASSWORD", "Password for CalDAV server") do |v|
32
- options[:password] = v
61
+ cli_endpoint[:password] = v
33
62
  end
34
63
 
35
64
  opts.on("-d", "--device DEVICE", "Serial device for Timex Datalink watch") do |v|
@@ -39,8 +68,14 @@ module TimexDatalinkCaldav
39
68
  opts.on("-a", "--api PROTOCOL_VERSION", "Protocol Version") do |v|
40
69
  options[:api] = v
41
70
  end
71
+
72
+ opts.on("-f", "--forward DAYS", Integer, "Number of days to look forward for events") do |v|
73
+ options[:days_forward] = v
74
+ end
42
75
  end.parse!(arguments)
76
+
77
+ options[:endpoints] = [cli_endpoint] if cli_endpoint.any? and options[:endpoints].nil?
43
78
  options
44
79
  end
45
80
  end
46
- end
81
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timex_datalink_caldav
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willy Hardy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-17 00:00:00.000000000 Z
11
+ date: 2023-05-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Adds a CLI and a feature to pull your next day of calendar events into
14
14
  the Timex Datalink watch. Note: Hardcoded protocol1 and EST timezone. At the moment.'
@@ -22,9 +22,12 @@ files:
22
22
  - CHANGELOG.md
23
23
  - Gemfile
24
24
  - Gemfile.lock
25
+ - LICENSE
25
26
  - README.md
26
27
  - Rakefile
27
28
  - bin/timex_datalink_caldav
29
+ - examples/README.md
30
+ - examples/caldav.yaml.sample
28
31
  - lib/timex_datalink_caldav.rb
29
32
  - lib/timex_datalink_caldav/client.rb
30
33
  - lib/timex_datalink_caldav/version.rb