-
Notifications
You must be signed in to change notification settings - Fork 0
/
scheduleRendered.groovy
executable file
·104 lines (84 loc) · 3.83 KB
/
scheduleRendered.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#!/usr/bin/env groovy
@GrabConfig(systemClassLoader = true)
@Grapes([
@Grab('info.picocli:picocli-groovy:4.7.3'),
@Grab('org.slf4j:slf4j-simple:2.0.7'),
@Grab('net.sourceforge.plantuml:plantuml:1.2023.10'),
@Grab('net.suteren.netatmo:netatmo4j:0.4.0')
])
@picocli.CommandLine.Command(name = "netatmoScheduleRenderer", description = "Visualize Netatmo schedule times.", mixinStandardHelpOptions = true)
@picocli.groovy.PicocliScript2
import com.fasterxml.jackson.databind.json.JsonMapper
import groovy.transform.Field
import net.sourceforge.plantuml.FileFormat
import net.sourceforge.plantuml.FileFormatOption
import net.sourceforge.plantuml.SourceStringReader
import net.suteren.netatmo.domain.therm.Schedule
import net.suteren.netatmo.domain.therm.TimetableEntry
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.simple.SimpleLogger
import picocli.CommandLine
import java.time.DayOfWeek
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.Temporal
import java.util.concurrent.atomic.AtomicInteger
@Field final static JSON_MAPPER = JsonMapper.builder().build()
@Field final static Map<Integer, String> ZONE_COLORS = [0: "GreenYellow", 1: "MediumSlateBlue", 2: "yellow", 3: "orange", 4: "cyan"]
@Field Map<Integer, String> zoneNames
@Field final Logger log = LoggerFactory.getLogger('scheduleRenderer')
@Field public static final int MINUTES_PER_DAY = 1440
@CommandLine.Parameters(arity = "1", paramLabel = "SECHEDULE", description = "Schedule JSON file")
@Field File scheduleFile
@CommandLine.Option(names = ["-i", "--renderImage"], description = "Render image or get plantuml source")
@Field boolean renderImage = false
@CommandLine.Option(names = ["-d", "--debug"], description = "Enable verbose logging")
@Field boolean debug = false
if (debug) {
System.setProperty(SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE")
}
@Field static final DateTimeFormatter WEEKDAY_FORMATTER = DateTimeFormatter.ofPattern('ccc')
@Field static final Temporal WEEKDAY_TEMPORAL = LocalDate.now()
Schedule schedule = JSON_MAPPER.readValue(scheduleFile, Schedule)
zoneNames = schedule.zones().collectEntries { [(it.id()): it.name()] }
List<TimetableEntry> timetable = schedule.timetable()
def days = timetable.groupBy { it.mOffset() / MINUTES_PER_DAY as int }
String source = """
@startuml
title Weekly schedule: ${schedule.name()}
concise "${formatDow(DayOfWeek.MONDAY)}" as d0
concise "${formatDow(DayOfWeek.TUESDAY)}" as d1
concise "${formatDow(DayOfWeek.WEDNESDAY)}" as d2
concise "${formatDow(DayOfWeek.THURSDAY)}" as d3
concise "${formatDow(DayOfWeek.FRIDAY)}" as d4
concise "${formatDow(DayOfWeek.SATURDAY)}" as d5
concise "${formatDow(DayOfWeek.SUNDAY)}" as d6
${renderDays(days)}
@enduml
"""
private static String formatDow(DayOfWeek dow) {
WEEKDAY_FORMATTER.format(WEEKDAY_TEMPORAL.with(dow))
}
if (!renderImage) {
println source
} else {
final ByteArrayOutputStream os = new ByteArrayOutputStream()
log.info(new SourceStringReader(source).outputImage(os, new FileFormatOption(FileFormat.SVG)).toString())
os.close()
println os.toString('UTF-8')
}
private String renderDays(Map<Integer, List<TimetableEntry>> days) {
AtomicInteger last = new AtomicInteger(days.get(0).first().zoneId())
days.collect { d, t -> "@d${d}\n${renderTimes(t, last)}" }.join('\n\n')
}
private String renderTimes(List<TimetableEntry> timetableEntries, AtomicInteger last) {
"0:00:00 is \"${zoneNames[last.get()]}\" #${getColor(last.getAndSet(timetableEntries.last().zoneId()))}\n" + timetableEntries.collect { "${offsetToTime(it)} is \"${zoneNames[it.zoneId()]}\" #${getColor(it.zoneId())}" }.join('\n') + "\n24:00:0 is {hidden}"
}
private static String getColor(int set) {
ZONE_COLORS[set] ?: "Lavender"
}
private static String offsetToTime(TimetableEntry it) {
def minutes = it.mOffset() % MINUTES_PER_DAY
"${minutes / 60 as int}:${minutes % 60}:00"
}